Completed
Pull Request — master (#594)
by Mateusz
03:09
created

DeploynautJob::alarmHandler()   C

Complexity

Conditions 7
Paths 4

Size

Total Lines 39
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 39
rs 6.7272
cc 7
eloc 24
nc 4
nop 0
1
<?php
2
3
use \SilverStripe\Platform\Core\Rainforest\Anthill;
4
use \SilverStripe\Platform\Core\Rainforest;
5
6
abstract class DeploynautJob implements DeploynautJobInterface {
7
8
	/**
9
	 * @var array
10
	 */
11
	public $args;
12
13
	abstract protected function updateStatus($status);
14
15
	/**
16
	 * Poll the sigFile looking for a signal to self-deliver.
17
	 * This is useful if we don't know the PID of the worker - we can easily deliver signals
18
	 * if we only know the ClassName and ID of the DataObject.
19
	 */
20
	public function alarmHandler() {
21
		$sigFile = $this->args['sigFile'];
22
		if (file_exists($sigFile) && is_readable($sigFile) && is_writable($sigFile)) {
23
			$signal = (int)file_get_contents($sigFile);
24
			if (is_int($signal) && in_array((int)$signal, [
25
				// The following signals are trapped by both Resque and Rainforest.
26
				SIGTERM,
27
				SIGINT,
28
				SIGQUIT,
29
				// The following are Resque only.
30
				SIGUSR1,
31
				SIGUSR2,
32
				SIGCONT
33
			])) {
34
				echo sprintf(
35
					'[-] Signal "%s" received, delivering to own process group, PID "%s".' . PHP_EOL,
36
					$signal,
37
					getmypid()
38
				);
39
40
				// Mark the signal as received.
41
				unlink($sigFile);
42
43
				// Dispatch to own process group.
44
				$pgid = posix_getpgid(getmypid());
45
				if ($pgid<=0) {
46
					echo sprintf(
47
						'[-] Unable to send signal to invalid PGID "%s".' . PHP_EOL,
48
						$pgid
49
					);
50
				} else {
51
					posix_kill(-$pgid, $signal);
52
				}
53
			}
54
		}
55
56
		// Wake up again soon.
57
		pcntl_alarm(1);
58
	}
59
60
	public function setUp() {
61
		// Make this process a session leader so we can send signals
62
		// to this job as a whole (including any subprocesses such as spawned by Symfony).
63
		posix_setsid();
64
65
		if(function_exists('pcntl_alarm') && function_exists('pcntl_signal')) {
66
			if (!empty($this->args['sigFile'])) {
67
				echo sprintf('[-] Signal file requested, polling "%s".' . PHP_EOL, $this->args['sigFile']);
68
				declare(ticks = 1);
69
				pcntl_signal(SIGALRM, [$this, 'alarmHandler']);
70
				pcntl_alarm(1);
71
			}
72
		}
73
74
		chdir(BASE_PATH);
75
	}
76
77
	/**
78
	 * {@inheritdoc}
79
	 */
80
	public function onFailure(Exception $exception) {
81
		$this->updateStatus('Failed');
82
	}
83
84
	public function runOp($opName, Anthill\Interfaces\Params $params, \Psr\Log\LoggerInterface $logger = null) {
85
		if (!$logger) {
86
			$logger = new \Psr\Log\NullLogger;
87
		}
88
		$container = Anthill\Anthill::bootstrap(
89
			// For now only operations that don't use the ClientFactory are supported.
90
			// This would ideally support passing platform-agnostic credentials so we could
91
			// support both capistrano and aws.
92
			null,
93
			$logger
94
		);
95
		$factory = $container->get('SilverStripe\Platform\Core\Rainforest\Anthill\RunnerFactory');
96
		$runner = $factory->getDefault($opName, $params);
97
		$runner->execute();
98
		return $runner;
99
	}
100
101
}
102