PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.11.0
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.11.0
4.11.0 4.10.0 4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Backup / Service / BeforeUpdateBackupRequest.php
wp-staging / Backup / Service Last commit date
Compression 1 day ago Database 1 day ago DirectoryExplorer 1 day ago AbstractBackgroundBackupRequest.php 1 day ago AbstractBackupsFinder.php 1 day ago AbstractExtractor.php 1 day ago AbstractServiceProvider.php 1 day ago Archiver.php 1 day ago BackupAssets.php 1 day ago BackupContent.php 1 day ago BackupMetadataEditor.php 1 day ago BackupMetadataReader.php 1 day ago BackupSigner.php 1 day ago BackupsDirectoryResolver.php 1 day ago BackupsFinder.php 1 day ago BeforeUpdateBackupRequest.php 1 day ago BeforeUpdateBackupsService.php 1 day ago Extractor.php 1 day ago FileBackupService.php 1 day ago FileBackupServiceProvider.php 1 day ago ServiceInterface.php 1 day ago TmpBackupCleaner.php 1 day ago UpdateProtectionHealth.php 1 day ago UpdateProtectionSettings.php 1 day ago ZlibCompressor.php 1 day ago
BeforeUpdateBackupRequest.php
266 lines
1 <?php
2
3 namespace WPStaging\Backup\Service;
4
5 use WPStaging\Core\WPStaging;
6 use WPStaging\Framework\Job\JobTransientCache;
7
8
9
10
11
12
13
14
15
16 class BeforeUpdateBackupRequest extends AbstractBackgroundBackupRequest
17 {
18
19 const OPTION_STATE = 'wpstg_backup_before_update_request';
20
21
22
23
24
25
26
27 const STALL_GRACE_IN_SECONDS = 5 * MINUTE_IN_SECONDS;
28
29
30 const MAX_REPORTED_MESSAGE_LENGTH = 200;
31
32
33 const OUTCOME_STARTED = 'started';
34 const OUTCOME_ALREADY_RUNNING = 'already_running';
35 const OUTCOME_FAILED = 'failed';
36
37
38 private $health;
39
40
41 private $failureReason = '';
42
43
44
45
46 public function __construct(UpdateProtectionHealth $health)
47 {
48 $this->health = $health;
49 }
50
51 const TRANSIENT_NUDGE_LOCK = 'wpstg_backup_before_update_nudge';
52
53 const ANALYTICS_GROUP = 'backup_before_update';
54
55 const EVENT_STARTED = 'before_update_backup_started';
56 const EVENT_COMPLETED = 'before_update_backup_completed';
57 const EVENT_FAILED = 'before_update_backup_failed';
58
59
60
61
62
63
64
65
66
67
68
69 public function startForUpdate(array $backupData, string $pluginFile = ''): string
70 {
71 if ($this->isPending()) {
72 $this->queuePlugin($pluginFile);
73
74 return self::OUTCOME_ALREADY_RUNNING;
75 }
76
77 $this->write([
78 'status' => self::STATUS_QUEUED,
79 'plugin_files' => $pluginFile === '' ? [] : [$pluginFile],
80 'queued_at' => time(),
81 'backup_job_id' => '',
82 ]);
83
84 if (!$this->start($backupData)) {
85 return self::OUTCOME_FAILED;
86 }
87
88 return self::OUTCOME_STARTED;
89 }
90
91
92
93
94
95
96
97
98
99
100
101 public function queuePlugin(string $pluginFile)
102 {
103 $waiting = $this->getPendingPluginFiles();
104
105 if ($pluginFile === '' || !$this->isPending() || in_array($pluginFile, $waiting, true)) {
106 return;
107 }
108
109 $waiting[] = $pluginFile;
110
111 $this->write(array_merge($this->read(), ['plugin_files' => $waiting]));
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 public function failIfStalled(): bool
129 {
130 if ($this->getStatus() !== self::STATUS_RUNNING || !$this->isOlderThanStallGrace()) {
131 return false;
132 }
133
134 if ($this->isBackupJobStillKnown()) {
135 return false;
136 }
137
138 $this->failureReason = UpdateProtectionHealth::REASON_STALLED;
139 $this->markFailed();
140
141 return true;
142 }
143
144
145
146
147
148 public function getPendingPluginFiles(): array
149 {
150 if (!$this->isPending()) {
151 return [];
152 }
153
154 $state = $this->read();
155
156 return (isset($state['plugin_files']) && is_array($state['plugin_files'])) ? $state['plugin_files'] : [];
157 }
158
159
160
161
162 protected function getOptionName(): string
163 {
164 return self::OPTION_STATE;
165 }
166
167
168
169
170 protected function getNudgeTransientName(): string
171 {
172 return self::TRANSIENT_NUDGE_LOCK;
173 }
174
175
176
177
178 protected function getEventNames(): array
179 {
180 return [
181 'started' => self::EVENT_STARTED,
182 'completed' => self::EVENT_COMPLETED,
183 'failed' => self::EVENT_FAILED,
184 ];
185 }
186
187
188
189
190 protected function getAnalyticsGroup(): string
191 {
192 return self::ANALYTICS_GROUP;
193 }
194
195
196
197
198 protected function getLogContext(): string
199 {
200 return 'WP STAGING Backup Before Update';
201 }
202
203
204
205
206
207
208
209
210
211 protected function afterFailed(string $reason = '')
212 {
213 $this->health->recordFailure($reason, $this->failureReason);
214 $this->failureReason = '';
215 }
216
217
218
219
220
221
222
223
224
225
226 protected function getFailureReport(string $reason): array
227 {
228 return [
229 'reason' => $this->failureReason !== '' ? $this->failureReason : $this->health->classify($reason),
230 'message' => substr($reason, 0, self::MAX_REPORTED_MESSAGE_LENGTH),
231 ];
232 }
233
234
235
236
237 private function isOlderThanStallGrace(): bool
238 {
239 $state = $this->read();
240 $startedAt = isset($state['started_at']) ? (int)$state['started_at'] : 0;
241
242 return $startedAt > 0 && $startedAt < time() - self::STALL_GRACE_IN_SECONDS;
243 }
244
245
246
247
248 private function isBackupJobStillKnown(): bool
249 {
250 $state = $this->read();
251 if (empty($state['backup_job_id'])) {
252 return false;
253 }
254
255 try {
256 $job = WPStaging::make(JobTransientCache::class)->getJob();
257 } catch (\Throwable $e) {
258
259
260 return true;
261 }
262
263 return is_array($job) && isset($job['queueId']) && $job['queueId'] === $state['backup_job_id'];
264 }
265 }
266