PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / trunk
WP STAGING – WordPress Backups, Restore, Migration & Clone vtrunk
4.11.1 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 week ago Database 1 week ago DirectoryExplorer 1 week ago AbstractBackgroundBackupRequest.php 4 days ago AbstractBackupsFinder.php 1 week ago AbstractExtractor.php 1 week ago AbstractServiceProvider.php 1 week ago Archiver.php 4 days ago BackupAssets.php 1 week ago BackupContent.php 1 week ago BackupMetadataEditor.php 4 days ago BackupMetadataReader.php 1 week ago BackupSigner.php 1 week ago BackupsDirectoryResolver.php 1 week ago BackupsFinder.php 1 week ago BeforeUpdateBackupRequest.php 1 week ago BeforeUpdateBackupsService.php 1 week ago Extractor.php 1 week ago FileBackupService.php 1 week ago FileBackupServiceProvider.php 1 week ago ServiceInterface.php 1 week ago TmpBackupCleaner.php 1 week ago UpdateProtectionHealth.php 1 week ago UpdateProtectionSettings.php 1 week ago ZlibCompressor.php 1 week 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