PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / trunk
GiveWP – Donation Plugin and Fundraising Platform vtrunk
4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / Framework / Migrations / Controllers / BatchMigrationRunner.php
give / src / Framework / Migrations / Controllers Last commit date
BatchMigrationRunner.php 1 year ago ManualMigration.php 5 months ago
BatchMigrationRunner.php
220 lines
1 <?php
2
3 namespace Give\Framework\Migrations\Controllers;
4
5 use ActionScheduler_Store;
6 use Exception;
7 use Give\Framework\Database\DB;
8 use Give\Framework\Migrations\Contracts\BatchMigration;
9 use Give\MigrationLog\MigrationLogStatus;
10
11 /**
12 * Batch Migration runner controller
13 *
14 * @since 4.0.0
15 */
16 class BatchMigrationRunner
17 {
18 /**
19 * @var BatchMigration
20 */
21 private $migration;
22
23 /**
24 * @var ActionScheduler_Store
25 */
26 private $actionSchedulerStore;
27
28 /**
29 * @since 4.0.0
30 */
31 public function __construct(BatchMigration $migration)
32 {
33 $this->migration = $migration;
34 $this->actionSchedulerStore = ActionScheduler_Store::instance();
35 }
36
37 /**
38 * Run batch migration
39 *
40 * @since 4.0.0
41 *
42 * @throws Exception
43 */
44 public function run(): string
45 {
46 $this->registerAction();
47
48 $actions = $this->actionSchedulerStore->query_actions([
49 'group' => $this->getGroup(),
50 'per_page' => 0,
51 ]);
52
53 if ( ! $actions) {
54 $itemsCount = $this->migration->getItemsCount();
55
56 // Bailout if there are no items to process
57 if ( ! $itemsCount) {
58 return MigrationLogStatus::SUCCESS;
59 }
60
61 $current = 0;
62 $batches = ceil($itemsCount / $this->migration->getBatchSize());
63
64 // Register migration action for each batch
65 for ($i = 0; $i < $batches; $i++) {
66 if ($items = $this->migration->getBatchItemsAfter($current)) {
67 [$firstId, $lastId] = $items;
68 $current = $lastId;
69 as_enqueue_async_action($this->getHook(), [$firstId, $lastId], $this->getGroup());
70 }
71 }
72
73 return MigrationLogStatus::RUNNING;
74 }
75
76 $pendingActions = (int)$this->actionSchedulerStore->query_actions([
77 'group' => $this->getGroup(),
78 'status' => [
79 ActionScheduler_Store::STATUS_RUNNING,
80 ActionScheduler_Store::STATUS_PENDING,
81 ],
82 ], 'count');
83
84 if ($pendingActions) {
85 return MigrationLogStatus::RUNNING;
86 }
87
88 $failedActions = (int)$this->actionSchedulerStore->query_actions([
89 'group' => $this->getGroup(),
90 'status' => [
91 ActionScheduler_Store::STATUS_FAILED,
92 ActionScheduler_Store::STATUS_CANCELED,
93 ],
94 ], 'count');
95
96 if ($failedActions) {
97 return MigrationLogStatus::INCOMPLETE;
98 }
99
100 // Run the last check
101 if ($this->migrationHasMoreItemsToBatch()) {
102 return MigrationLogStatus::RUNNING;
103 }
104
105 // If everything went well, delete scheduled actions
106 foreach ($actions as $actionId) {
107 $this->actionSchedulerStore->delete_action($actionId);
108 }
109
110 return MigrationLogStatus::SUCCESS;
111 }
112
113 /**
114 * @since 4.0.0
115 */
116 private function getHook(): string
117 {
118 return 'givewp-batch-' . $this->migration::id();
119 }
120
121 /**
122 * @since 4.0.0
123 */
124 private function getGroup(): string
125 {
126 return $this->migration::id();
127 }
128
129 /**
130 * Register batch migration action
131 *
132 * @since 4.0.0
133 *
134 * @throws Exception
135 */
136 private function registerAction()
137 {
138 add_action($this->getHook(), function ($firstId, $lastId) {
139 DB::beginTransaction();
140
141 try {
142 $this->migration->runBatch($firstId, $lastId);
143
144 DB::commit();
145 } catch (Exception $e) {
146 DB::rollback();
147 throw new Exception($e->getMessage(), 0, $e);
148 }
149 }, 10, 2);
150 }
151
152
153 /**
154 * Check if the current migration has new data
155 *
156 * @since 4.0.0
157 */
158 private function migrationHasMoreItemsToBatch(): bool
159 {
160 // todo: We already have a list of all actions in run method, maybe we can simply pass end($actions) to this method?
161
162 // Get the last completed action
163 $actionId = $this->actionSchedulerStore->query_action([
164 'group' => $this->getGroup(),
165 'per_page' => 1,
166 'status' => ActionScheduler_Store::STATUS_COMPLETE,
167 'order' => 'DESC',
168 'orderby' => 'action_id',
169 ]);
170
171 $action = $this->actionSchedulerStore->fetch_action($actionId);
172
173 [, $lastId] = $action->get_args();
174
175 // bailout if for some strange reason we can't get the last id
176 if ( ! $lastId) {
177 return false;
178 }
179
180 if ($this->migration->hasMoreItemsToBatch($lastId)) {
181 as_enqueue_async_action($this->getHook(), [$lastId, null], $this->getGroup());
182
183 return true;
184 }
185
186 return false;
187 }
188
189 /**
190 * Reschedule failed and canceled actions
191 *
192 * @since 4.0.0
193 */
194 public function rescheduleFailedActions()
195 {
196 $failedActions = $this->actionSchedulerStore->query_actions([
197 'group' => $this->getGroup(),
198 'per_page' => 0,
199 'status' => [
200 ActionScheduler_Store::STATUS_FAILED,
201 ActionScheduler_Store::STATUS_CANCELED,
202 ],
203 ]);
204
205 if ( ! is_array($failedActions)) {
206 return;
207 }
208
209 foreach ($failedActions as $actionId) {
210 $action = $this->actionSchedulerStore->fetch_action($actionId);
211
212 // Reschedule new action
213 as_enqueue_async_action($this->getHook(), $action->get_args(), $this->getGroup());
214
215 // Delete failed action
216 $this->actionSchedulerStore->delete_action($actionId);
217 }
218 }
219 }
220