Completed
Push — master ( 01dfa3...bd9515 )
by C
05:18
created

AbstractDaemonCommand::attachPid()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 19
ccs 11
cts 11
cp 1
rs 9.4285
cc 3
eloc 10
nc 4
nop 2
crap 3
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
		{
54 23
			if ($fs->has($pidFile))
55
			{
56 4
				$pids = array_filter(explode(':', $fs->read($pidFile)['contents']));
57 4
				if (!empty($pids))
58
				{
59 3
					$runningPids = [];
60 3
					foreach ($pids as $key => $pid)
61
					{
62 3
						if (!Util::isPidRunning($pid))
63
						{
64 2
							continue;
65
						}
66
67 2
						$runningPids[$key] = $pid;
68
					}
69
70 3
					if ($runningPids == $pids)
71
					{
72 1
						$this->log('Daemon for command ' . $this->getName() . ' is already running with the pids ' . implode(':', $pids),
73 1
								Logger::INFO);
74 1
						return;
75
					}
76
					else
77
					{
78
						// Killing all running processes and starting again
79 2
						foreach ($runningPids as $pid)
80
						{
81 1
							$this->killPid($pid);
82
						}
83 2
						$fs->delete($pidFile);
84
					}
85
				}
86
			}
87
88 22
			if ($background)
89
			{
90
				// Stripping out the not needed tokens
91 1
				$inputString = (string)$input;
92 1
				$inputString = str_replace([
93 1
						'-b ',
94 1
						'--backgound ',
95 1
						$this->getName() . ' '
96 1
				], '', $inputString);
97
98 1
				$command = Command::getAppCommand($this->getName());
99 1
				$command->setAsync(true);
100 1
				$command->setCaptureErrorInOutput(true);
101 1
				$command->addArgument($inputString, false);
102 1
				$this->getCommandRunner()->execute($command);
103
104 1
				$this->log('Started daeomon for command ' . $this->getName() . ' in background mode.', Logger::INFO);
105 1
				return;
106
			}
107
108 21
			$this->attachPid($input, getmypid());
109
110 21
			$this->doWork($input, $output);
111 21
			$fs->delete($pidFile);
112
		}
113 22
		if ($action == 'stop' && $fs->has($pidFile))
114
		{
115 1
			$pids = explode(':', $fs->read($pidFile)['contents']);
116 1
			if (!empty($pids))
117
			{
118 1
				$this->log('Daemon for command ' . $this->getName() . ' is running with the pids ' . implode(':', $pids) . ' killing it',
119 1
						Logger::INFO);
120
121 1
				foreach ($pids as $pid)
122
				{
123 1
					if (!Util::isPidRunning($pid))
124
					{
125 1
						continue;
126
					}
127 1
					$this->killPid($pid);
128
				}
129
			}
130 1
			$fs->delete($pidFile);
131
132 1
			$this->log('Daemon for command ' . $this->getName() . ' stopped', Logger::INFO);
133
		}
134 22
	}
135
136
	/**
137
	 *
138
	 * @return \Tartana\Component\Command\Runner
139
	 */
140 5
	protected function getCommandRunner()
141
	{
142 5
		return $this->commandRunner;
143
	}
144
145 21
	protected function attachPid(InputInterface $input, $pid)
146
	{
147 21
		$environment = $input->getOption('env');
148
149 21
		$pidFile = $this->getName() . '_' . $environment . '.pid';
150 21
		$fs = new Local(TARTANA_PATH_ROOT . '/var/tmp/');
151
152 21
		$pids = [];
153 21
		if ($fs->has($pidFile))
154
		{
155 3
			$pids = array_filter(explode(':', $fs->read($pidFile)['contents']));
156
		}
157 21
		if (!in_array($pid, $pids))
158
		{
159 21
			$pids[] = $pid;
160
		}
161
162 21
		$fs->write($pidFile, implode(':', $pids), new Config());
163 21
	}
164
165 2
	private function killPid($pid)
166
	{
167 2
		$command = new Command('kill');
168 2
		$command->addArgument('-9');
169 2
		$command->addArgument($pid);
170
171 2
		$output = $this->getCommandRunner()->execute($command);
172 2
		$this->log('Output of daemon ' . $this->getName() . ' kill is for pid ' . $pid . ' is: ' . $output);
173 2
	}
174
}
175