Completed
Pull Request — master (#602)
by Sean
09:27 queued 05:11
created

DeployJob   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 178
Duplicated Lines 17.98 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 10
Bugs 1 Features 1
Metric Value
wmc 24
c 10
b 1
f 1
lcom 1
cbo 8
dl 32
loc 178
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
C alarmHandler() 0 39 7
A setUp() 0 17 4
C perform() 22 70 7
A onFailure() 0 3 1
A updateStatus() 0 6 1
A updateBackupStatus() 10 10 3
A DNData() 0 3 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 View Code Duplication
			if($backupDataTransfer) {
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...
120
				$log->write('Backing up existing data');
121
				try {
122
					$environment->Backend()->dataTransfer($backupDataTransfer, $log);
123
					$this->updateBackupStatus('Finished');
124
				} catch(Exception $e) {
125
					$this->updateBackupStatus('Failed');
126
					throw $e;
127
				}
128
			}
129
130
			$environment->Backend()->deploy(
131
				$environment,
132
				$log,
133
				$project,
134
				// Pass all args to give the backend full visibility. These args also contain
135
				// all options from the DeploymentStrategy merged in, including sha.
136
				$this->args
137
			);
138
		} catch(Exception $e) {
139
			// DeploynautJob will automatically trigger onFailure.
140
			echo "[-] DeployJob failed" . PHP_EOL;
141
			throw $e;
142
		}
143
		$this->updateStatus(DNDeployment::TR_COMPLETE);
144
		echo "[-] DeployJob finished" . PHP_EOL;
145
	}
146
147
	public function onFailure(Exception $exception) {
148
		$this->updateStatus(DNDeployment::TR_FAIL);
149
	}
150
151
	/**
152
	 * @param string $status Transition
153
	 * @global array $databaseConfig
154
	 */
155
	protected function updateStatus($status) {
156
		global $databaseConfig;
157
		DB::connect($databaseConfig);
158
		$deployment = DNDeployment::get()->byID($this->args['deploymentID']);
159
		$deployment->getMachine()->apply($status);
160
	}
161
162
	/**
163
	 * @param string $status Status of DNDataTransfer
164
	 * @global array $databaseConfig
165
	 */
166 View Code Duplication
	protected function updateBackupStatus($status) {
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...
167
		global $databaseConfig;
168
		DB::connect($databaseConfig);
169
		$deployment = DNDeployment::get()->byID($this->args['deploymentID']);
170
		$backup = $deployment->BackupDataTransfer();
171
		if($backup && $backup->exists()) {
172
			$backup->Status = $status;
173
			$backup->write();
174
		}
175
	}
176
177
	/**
178
	 * @return DNData
179
	 */
180
	protected function DNData() {
181
		return DNData::inst();
182
	}
183
}
184