AbstractDaemonCommand::execute()   D
last analyzed

Complexity

Conditions 14
Paths 16

Size

Total Lines 82
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 53
CRAP Score 14

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 82
ccs 53
cts 53
cp 1
rs 4.955
cc 14
eloc 53
nc 16
nop 2
crap 14

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Tartana\Console\Command;
3
4
use League\Flysystem\Adapter\Local;
5
use Monolog\Logger;
6
use Symfony\Component\Console\Input\InputArgument;
7
use Symfony\Component\Console\Input\InputInterface;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use Tartana\Component\Command\Command;
11
use Tartana\Component\Command\Runner;
12
use Tartana\Mixins\LoggerAwareTrait;
13
use Tartana\Util;
14
use League\Flysystem\Config;
15
16
abstract class AbstractDaemonCommand extends \Symfony\Component\Console\Command\Command
17
{
18
	use LoggerAwareTrait;
19
20
	private $commandRunner = null;
21
22 25
	public function __construct(Runner $commandRunner)
23
	{
24 25
		parent::__construct();
25
26 25
		$this->commandRunner = $commandRunner;
27 25
	}
28
29
	/**
30
	 * The long running work.
31
	 *
32
	 * @param InputInterface $input
33
	 * @param OutputInterface $output
34
	 */
35
	abstract protected function doWork(InputInterface $input, OutputInterface $output);
36
37 25
	protected function configure()
38
	{
39 25
		$this->addArgument('action', InputArgument::OPTIONAL, 'The action, can be start or stop.', 'start');
40 25
		$this->addOption('background', 'b', InputOption::VALUE_NONE, 'Should start on background.');
41 25
	}
42
43 24
	protected function execute(InputInterface $input, OutputInterface $output)
44
	{
45
		// Getting arguments
46 24
		$action      = $input->getArgument('action');
47 24
		$environment = $input->getOption('env');
48 24
		$background  = (boolean)$input->getOption('background');
49
50 24
		$pidFile = $this->getName() . '_' . $environment . '.pid';
51 24
		$fs      = new Local(TARTANA_PATH_ROOT . '/var/tmp/');
52 24
		if ($action == 'start') {
53 23
			if ($fs->has($pidFile)) {
54 3
				$pids = array_filter(explode(':', $fs->read($pidFile)['contents']));
55 3
				if (!empty($pids)) {
56 2
					$runningPids = [];
57 2
					foreach ($pids as $key => $pid) {
58 2
						if (!Util::isPidRunning($pid)) {
59 1
							continue;
60
						}
61
62 2
						$runningPids[$key] = $pid;
63
					}
64
65 2
					if ($runningPids == $pids) {
66 1
						$this->log(
67 1
							'Daemon for command ' . $this->getName() . ' is already running with the pids ' . implode(':', $pids),
68 1
							Logger::INFO
69
						);
70 1
						return;
71
					} else {
72
						// Killing all running processes and starting again
73 1
						foreach ($runningPids as $pid) {
74 1
							$this->killPid($pid);
75
						}
76 1
						$fs->delete($pidFile);
77
					}
78
				}
79
			}
80
81 22
			if ($background) {
82
				// Stripping out the not needed tokens
83 1
				$inputString = (string)$input;
84 1
				$inputString = str_replace([
85 1
					'-b ',
86 1
					'--backgound ',
87 1
					$this->getName() . ' '
88 1
				], '', $inputString);
89
90 1
				$command = Command::getAppCommand($this->getName());
91 1
				$command->setAsync(true);
92 1
				$command->setCaptureErrorInOutput(true);
93 1
				$command->addArgument($inputString, false);
94 1
				$this->getCommandRunner()->execute($command);
95
96 1
				$this->log('Started daemon for command ' . $this->getName() . ' in background mode.', Logger::INFO);
97 1
				return;
98
			}
99
100 21
			$this->attachPid($input, getmypid());
101
102 21
			$this->doWork($input, $output);
103 21
			$fs->delete($pidFile);
104
		}
105 22
		if ($action == 'stop' && $fs->has($pidFile)) {
106 1
			$pids = explode(':', $fs->read($pidFile)['contents']);
107 1
			if (!empty($pids)) {
108 1
				$this->log(
109 1
					'Daemon for command ' . $this->getName() . ' is running with the pids ' . implode(':', $pids) . ' killing it',
110 1
					Logger::INFO
111
				);
112
113 1
				foreach ($pids as $pid) {
114 1
					if (!Util::isPidRunning($pid)) {
115 1
						continue;
116
					}
117 1
					$this->killPid($pid);
118
				}
119
			}
120 1
			$fs->delete($pidFile);
121
122 1
			$this->log('Daemon for command ' . $this->getName() . ' stopped', Logger::INFO);
123
		}
124 22
	}
125
126
	/**
127
	 *
128
	 * @return \Tartana\Component\Command\Runner
129
	 */
130 20
	protected function getCommandRunner()
131
	{
132 20
		return $this->commandRunner;
133
	}
134
135 21
	protected function attachPid(InputInterface $input, $pid)
136
	{
137 21
		$environment = $input->getOption('env');
138
139 21
		$pidFile = $this->getName() . '_' . $environment . '.pid';
140 21
		$fs      = new Local(TARTANA_PATH_ROOT . '/var/tmp/');
141
142 21
		$pids = [];
143 21
		if ($fs->has($pidFile)) {
144 3
			$pids = array_filter(explode(':', $fs->read($pidFile)['contents']));
145
		}
146 21
		if (!in_array($pid, $pids)) {
147 21
			$pids[] = $pid;
148
		}
149
150 21
		$fs->write($pidFile, implode(':', $pids), new Config());
151 21
	}
152
153 2
	private function killPid($pid)
154
	{
155 2
		$command = new Command('kill');
156 2
		$command->addArgument('-9');
157 2
		$command->addArgument($pid);
158
159 2
		$output = $this->getCommandRunner()->execute($command);
160 2
		$this->log('Output of daemon ' . $this->getName() . ' kill is for pid ' . $pid . ' is: ' . $output);
161 2
	}
162
}
163