Completed
Push — master ( 3dfec0...098987 )
by Sam
03:00
created

InstanceStateManager::getSubscribedEvents()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 1
eloc 6
nc 1
nop 0
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\InstanceCollectionEvent;
9
use Jalle19\StatusManager\Event\InstanceStateEvent;
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
	public function __construct(Configuration $configuration, LoggerInterface $logger, EventDispatcher $eventDispatcher)
44
	{
45
		parent::__construct($configuration, $logger, $eventDispatcher);
46
47
		$this->_instances = new \SplObjectStorage();
48
49
		// Attach a state to each instance
50
		foreach ($configuration->getInstances() as $instance)
51
			$this->_instances->attach($instance, new InstanceState());
52
	}
53
54
55
	/**
56
	 * @inheritdoc
57
	 */
58
	public static function getSubscribedEvents()
59
	{
60
		return [
61
			Events::INSTANCE_COLLECTION_REQUEST    => 'onInstanceCollectionRequest',
62
			Events::INSTANCE_STATE_REACHABLE       => 'onInstanceReachable',
63
			Events::INSTANCE_STATE_UNREACHABLE     => 'onInstanceUnreachable',
64
			Events::INSTANCE_STATE_MAYBE_REACHABLE => 'onInstanceMaybeReachable',
65
		];
66
	}
67
68
69
	/**
70
	 * Handler for the INSTANCE_COLLECTION_REQUEST event
71
	 */
72
	public function onInstanceCollectionRequest()
73
	{
74
		// Respond with the instances and their current state
75
		$this->eventDispatcher
76
			->dispatch(Events::INSTANCE_COLLECTION, new InstanceCollectionEvent($this->_instances));
77
	}
78
79
80
	/**
81
	 * Called when an instance was tried and reachable
82
	 *
83
	 * @param InstanceStateEvent $event
84
	 */
85 View Code Duplication
	public function onInstanceReachable(InstanceStateEvent $event)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
86
	{
87
		$instance      = $event->getInstance();
88
		$instanceState = $this->getInstanceState($instance);
89
90
		// Update reachability state now that we know the instance is reachable
91
		if ($instanceState->getReachability() === InstanceState::MAYBE_REACHABLE)
92
		{
93
			$this->logger
94
				->info('Instance {instanceName} is now reachable, will start polling for updates', [
95
					'instanceName' => $instance->getName(),
96
				]);
97
98
			$instanceState->setReachability(InstanceState::REACHABLE);
99
		}
100
	}
101
102
103
	/**
104
	 * Called when an instance was tried and wasn't reachable
105
	 *
106
	 * @param InstanceStateEvent $event
107
	 */
108 View Code Duplication
	public function onInstanceUnreachable(InstanceStateEvent $event)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109
	{
110
		$instance      = $event->getInstance();
111
		$instanceState = $this->getInstanceState($instance);
112
113
		// Mark the instance as unreachable
114
		$message = 'Instance {instanceName} not reachable, will wait for {cycles} cycles before retrying';
115
116
		$this->logger->alert($message, [
117
			'instanceName' => $instance->getName(),
118
			'cycles'       => self::UNREACHABLE_CYCLES_UNTIL_RETRY,
119
		]);
120
121
		$instanceState->setReachability(InstanceState::UNREACHABLE);
122
	}
123
124
125
	/**
126
	 * Called when a previously unreachable instance was left untried for the current tick
127
	 *
128
	 * @param InstanceStateEvent $event
129
	 */
130
	public function onInstanceMaybeReachable(InstanceStateEvent $event)
131
	{
132
		$instance      = $event->getInstance();
133
		$instanceState = $this->getInstanceState($instance);
134
135
		// Wait for some cycles and then mark unreachable instances as maybe reachable
136
		if ($instanceState->getRetryCount() === self::UNREACHABLE_CYCLES_UNTIL_RETRY - 1)
137
		{
138
			$instanceState->setReachability(InstanceState::MAYBE_REACHABLE);
139
			$instanceState->resetRetryCount();
140
141
			$this->logger->info('Retrying instance {instanceName} during next cycle', [
142
				'instanceName' => $instance->getName(),
143
			]);
144
		}
145
		else
146
			$instanceState->incrementRetryCount();
147
	}
148
149
150
	/**
151
	 * @param Instance $instance
152
	 *
153
	 * @return InstanceState
154
	 */
155
	private function getInstanceState(Instance $instance)
156
	{
157
		return $this->_instances[$instance];
158
	}
159
160
}
161