Completed
Push — master ( 17c171...fcd6af )
by Mateusz
04:34 queued 01:02
created

DeployJob::perform()   B

Complexity

Conditions 5
Paths 36

Size

Total Lines 61
Code Lines 39

Duplication

Lines 12
Ratio 19.67 %

Importance

Changes 8
Bugs 1 Features 0
Metric Value
c 8
b 1
f 0
dl 12
loc 61
rs 8.6806
cc 5
eloc 39
nc 36
nop 0

How to fix   Long Method   

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
3
/**
4
 * Runs a deployment via the most appropriate backend
5
 */
6
class DeployJob extends DeploynautJob {
7
8
	/**
9
	 * @var array
10
	 */
11
	public $args;
12
13
	/**
14
	 * Poll the sigFile looking for a signal to self-deliver.
15
	 * This is useful if we don't know the PID of the worker - we can easily deliver signals
16
	 * if we only know the ClassName and ID of the DataObject.
17
	 */
18
	public function alarmHandler() {
19
		$sigFile = $this->args['sigFile'];
20
		if (file_exists($sigFile) && is_readable($sigFile) && is_writable($sigFile)) {
21
			$signal = (int)file_get_contents($sigFile);
22
			if (is_int($signal) && in_array((int)$signal, [
23
				// The following signals are trapped by both Resque and Rainforest.
24
				SIGTERM,
25
				SIGINT,
26
				SIGQUIT,
27
				// The following are Resque only.
28
				SIGUSR1,
29
				SIGUSR2,
30
				SIGCONT
31
			])) {
32
				echo sprintf(
33
					'[-] Signal "%s" received, delivering to own process group, PID "%s".' . PHP_EOL,
34
					$signal,
35
					getmypid()
36
				);
37
38
				// Mark the signal as received.
39
				unlink($sigFile);
40
41
				// Dispatch to own process group.
42
				$pgid = posix_getpgid(getmypid());
43
				if ($pgid<=0) {
44
					echo sprintf(
45
						'[-] Unable to send signal to invalid PGID "%s".' . PHP_EOL,
46
						$pgid
47
					);
48
				} else {
49
					posix_kill(-$pgid, $signal);
50
				}
51
			}
52
		}
53
54
		// Wake up again soon.
55
		pcntl_alarm(1);
56
	}
57
58
	public function setUp() {
59
		// Make this process a session leader so we can send signals
60
		// to this job as a whole (including any subprocesses such as spawned by Symfony).
61
		posix_setsid();
62
63
		if(function_exists('pcntl_alarm') && function_exists('pcntl_signal')) {
64
			if (!empty($this->args['sigFile'])) {
65
				echo sprintf('[-] Signal file requested, polling "%s".' . PHP_EOL, $this->args['sigFile']);
66
				declare(ticks = 1);
67
				pcntl_signal(SIGALRM, [$this, 'alarmHandler']);
68
				pcntl_alarm(1);
69
			}
70
		}
71
72
		$this->updateStatus(DNDeployment::TR_DEPLOY);
73
		chdir(BASE_PATH);
74
	}
75
76
	public function perform() {
77
		echo "[-] DeployJob starting" . PHP_EOL;
78
		$log = new DeploynautLogFile($this->args['logfile']);
79
80
		$deployment = DNDeployment::get()->byID($this->args['deploymentID']);
81
		$environment = $deployment->Environment();
82
		$project = $environment->Project();
83
		$backupDataTransfer = null;
84
		$backupMode = !empty($this->args['backup_mode']) ? $this->args['backup_mode'] : 'db';
85
86
		// Perform pre-deploy backup here if required. Note that the backup is done here within
87
		// the deploy job, so that the order of backup is done before deployment, and so it
88
		// doesn't tie up another worker. It also puts the backup output into
89
		// the same log as the deployment so there is visibility on what is going on.
90 View Code Duplication
		if(!empty($this->args['predeploy_backup'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
91
			$backupDataTransfer = DNDataTransfer::create();
92
			$backupDataTransfer->EnvironmentID = $environment->ID;
93
			$backupDataTransfer->Direction = 'get';
94
			$backupDataTransfer->Mode = $backupMode;
95
			$backupDataTransfer->ResqueToken = $deployment->ResqueToken;
96
			$backupDataTransfer->AuthorID = $deployment->DeployerID;
97
			$backupDataTransfer->write();
98
99
			$deployment->BackupDataTransferID = $backupDataTransfer->ID;
100
			$deployment->write();
101
		}
102
103
		// This is a bit icky, but there is no easy way of capturing a failed deploy by using the PHP Resque
104
		try {
105
			// Disallow concurrent deployments (don't rely on queuing implementation to restrict this)
106
			// Only consider deployments started in the last 30 minutes (older jobs probably got stuck)
107
			$runningDeployments = $environment->runningDeployments()->exclude('ID', $this->args['deploymentID']);
108
			if($runningDeployments->count()) {
109
				$runningDeployment = $runningDeployments->first();
110
				$message = sprintf(
111
					'Error: another deployment is in progress (started at %s by %s)',
112
					$runningDeployment->dbObject('Created')->Nice(),
113
					$runningDeployment->Deployer()->Title
114
				);
115
				$log->write($message);
116
				throw new \RuntimeException($message);
117
			}
118
119
			$this->performBackup($backupDataTransfer, $log);
120
			$environment->Backend()->deploy(
121
				$environment,
122
				$log,
123
				$project,
124
				// Pass all args to give the backend full visibility. These args also contain
125
				// all options from the DeploymentStrategy merged in, including sha.
126
				$this->args
127
			);
128
		} catch(Exception $e) {
129
			// DeploynautJob will automatically trigger onFailure.
130
			echo "[-] DeployJob failed" . PHP_EOL;
131
			throw $e;
132
		}
133
134
		$this->updateStatus(DNDeployment::TR_COMPLETE);
135
		echo "[-] DeployJob finished" . PHP_EOL;
136
	}
137
138
	public function onFailure(Exception $exception) {
139
		$this->updateStatus(DNDeployment::TR_FAIL);
140
	}
141
142 View Code Duplication
	protected function performBackup($backupDataTransfer, DeploynautLogFile $log) {
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...
143
		if (!$backupDataTransfer) {
144
			return false;
145
		}
146
147
		$log->write('Backing up existing data');
148
		try {
149
			$dataTransfer->Environment()->Backend()->dataTransfer($backupDataTransfer, $log);
0 ignored issues
show
Bug introduced by
The variable $dataTransfer does not exist. Did you mean $backupDataTransfer?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
150
			global $databaseConfig;
151
			DB::connect($databaseConfig);
152
			$backupDataTransfer->Status = 'Finished';
153
			$backupDataTransfer->write();
154
		} catch(Exception $e) {
155
			global $databaseConfig;
156
			DB::connect($databaseConfig);
157
			$backupDataTransfer->Status = 'Failed';
158
			$backupDataTransfer->write();
159
			throw $e;
160
		}
161
	}
162
163
	/**
164
	 * @param string $status Transition
165
	 * @global array $databaseConfig
166
	 */
167
	protected function updateStatus($status) {
168
		global $databaseConfig;
169
		DB::connect($databaseConfig);
170
		$deployment = DNDeployment::get()->byID($this->args['deploymentID']);
171
		$deployment->getMachine()->apply($status);
172
	}
173
174
	/**
175
	 * @return DNData
176
	 */
177
	protected function DNData() {
178
		return DNData::inst();
179
	}
180
}
181