InstanceStateManager::onInstanceMaybeReachable()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 9
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 17
rs 9.9666
ccs 12
cts 12
cp 1
crap 2
1
<?php
2
3
namespace Jalle19\StatusManager\Manager;
4
5
use Jalle19\StatusManager\Configuration\Configuration;
6
use Jalle19\StatusManager\Configuration\Instance;
7
use Jalle19\StatusManager\Event\Events;
8
use Jalle19\StatusManager\Event\InstanceStateEvent;
9
use Jalle19\StatusManager\Event\InstanceStatusCollectionRequestEvent;
10
use Jalle19\StatusManager\Instance\InstanceState;
11
use Psr\Log\LoggerInterface;
12
use Symfony\Component\EventDispatcher\EventDispatcher;
13
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
14
15
/**
16
 * Keeps track of the reachability for all configures instances.
17
 *
18
 * @package   Jalle19\StatusManager\Manager
19
 * @copyright Copyright &copy; Sam Stenvall 2016-
20
 * @license   https://www.gnu.org/licenses/gpl.html The GNU General Public License v2.0
21
 */
22
class InstanceStateManager extends AbstractManager implements EventSubscriberInterface
23
{
24
25
	/**
26
	 * The number of cycles to wait until retrying an unreachable instance
27
	 */
28
	const UNREACHABLE_CYCLES_UNTIL_RETRY = 10;
29
30
	/**
31
	 * @var \SplObjectStorage the instances to connect to and their individual state
32
	 */
33
	private $_instances;
34
35
36
	/**
37
	 * InstanceStateManager constructor.
38
	 *
39
	 * @param Configuration   $configuration
40
	 * @param LoggerInterface $logger
41
	 * @param EventDispatcher $eventDispatcher
42
	 */
43 2
	public function __construct(Configuration $configuration, LoggerInterface $logger, EventDispatcher $eventDispatcher)
44
	{
45 2
		parent::__construct($configuration, $logger, $eventDispatcher);
46
47 2
		$this->_instances = new \SplObjectStorage();
48
49
		// Attach a state to each instance
50 2
		foreach ($configuration->getInstances() as $instance)
51 2
			$this->_instances->attach($instance, new InstanceState());
52 2
	}
53
54
55
	/**
56
	 * @inheritdoc
57
	 */
58 2
	public static function getSubscribedEvents()
59
	{
60
		return [
61 2
			Events::INSTANCE_STATUS_COLLECTION_REQUEST => 'onInstanceStatusCollectionRequest',
62 2
			Events::INSTANCE_STATE_REACHABLE           => 'onInstanceReachable',
63 2
			Events::INSTANCE_STATE_UNREACHABLE         => 'onInstanceUnreachable',
64 2
			Events::INSTANCE_STATE_MAYBE_REACHABLE     => 'onInstanceMaybeReachable',
65 2
		];
66
	}
67
68
69
	/**
70
	 * Handler for the INSTANCE_STATUS_COLLECTION_EVENT event
71
	 *
72
	 * @param InstanceStatusCollectionRequestEvent $event
73
	 */
74
	public function onInstanceStatusCollectionRequest(InstanceStatusCollectionRequestEvent $event)
75
	{
76
		$event->setInstanceCollection($this->_instances);
77
	}
78
79
80
	/**
81
	 * Called when an instance was tried and reachable
82
	 *
83
	 * @param InstanceStateEvent $event
84
	 */
85 1
	public function onInstanceReachable(InstanceStateEvent $event)
86
	{
87 1
		$instance      = $event->getInstance();
88 1
		$instanceState = $this->getInstanceState($instance);
89
90
		// Update reachability state now that we know the instance is reachable
91 1
		if ($instanceState->getReachability() === InstanceState::MAYBE_REACHABLE)
92 1
		{
93 1
			$this->logger->notice('Instance {instanceName} is now reachable, will start polling for updates', [
94 1
				'instanceName' => $instance->getName(),
95 1
			]);
96
97 1
			$instanceState->setReachability(InstanceState::REACHABLE);
98 1
		}
99 1
	}
100
101
102
	/**
103
	 * Called when an instance was tried and wasn't reachable
104
	 *
105
	 * @param InstanceStateEvent $event
106
	 */
107 1
	public function onInstanceUnreachable(InstanceStateEvent $event)
108
	{
109 1
		$instance      = $event->getInstance();
110 1
		$instanceState = $this->getInstanceState($instance);
111
112
		// Mark the instance as unreachable
113 1
		$message = 'Instance {instanceName} not reachable, will wait for {cycles} cycles before retrying';
114
115 1
		$this->logger->warning($message, [
116 1
			'instanceName' => $instance->getName(),
117 1
			'cycles'       => self::UNREACHABLE_CYCLES_UNTIL_RETRY,
118 1
		]);
119
120 1
		$instanceState->setReachability(InstanceState::UNREACHABLE);
121 1
	}
122
123
124
	/**
125
	 * Called when a previously unreachable instance was left untried for the current tick
126
	 *
127
	 * @param InstanceStateEvent $event
128
	 */
129 1
	public function onInstanceMaybeReachable(InstanceStateEvent $event)
130
	{
131 1
		$instance      = $event->getInstance();
132 1
		$instanceState = $this->getInstanceState($instance);
133
134
		// Wait for some cycles and then mark unreachable instances as maybe reachable
135 1
		if ($instanceState->getRetryCount() === self::UNREACHABLE_CYCLES_UNTIL_RETRY - 1)
136 1
		{
137 1
			$instanceState->setReachability(InstanceState::MAYBE_REACHABLE);
138 1
			$instanceState->resetRetryCount();
139
140 1
			$this->logger->info('Retrying instance {instanceName} during next cycle', [
141 1
				'instanceName' => $instance->getName(),
142 1
			]);
143 1
		}
144
		else
145 1
			$instanceState->incrementRetryCount();
146 1
	}
147
148
149
	/**
150
	 * @param Instance $instance
151
	 *
152
	 * @return InstanceState
153
	 */
154 1
	public function getInstanceState(Instance $instance)
155
	{
156 1
		return $this->_instances[$instance];
157
	}
158
159
}
160