PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.18.0
GiveWP – Donation Plugin and Fundraising Platform v4.18.0
4.18.0 4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 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 All 257 releases
← All changes | src/Framework/Migrations/MigrationsRunner.php +113 -92 4.16.5 → 4.18.0 View file →
@@ -11,8 +11,9 @@
11 11 use Give\Log\Log;
12 12 use Give\MigrationLog\MigrationLogFactory;
13 13 use Give\MigrationLog\MigrationLogRepository;
14 14 use Give\MigrationLog\MigrationLogStatus;
15 +use WP_Upgrader;
15 16
16 17 /**
17 18 * Class MigrationsRunner
18 19 *
@@ -20,8 +21,13 @@
20 21 */
21 22 class MigrationsRunner
22 23 {
23 24 /**
25 + * @since 4.18.0
26 + */
27 + const LOCK_NAME = 'give_migrations';
28 +
29 + /**
24 30 * List of completed migrations.
25 31 *
26 32 * @since 2.9.0
27 33 *
@@ -69,8 +75,9 @@
69 75
70 76 /**
71 77 * Run database migrations.
72 78 *
79 + * @since 4.18.0 hold a lock so concurrent requests do not run the same migration twice
73 80 * @since 4.0.0 add support for batch processing
74 81 * @since 2.9.0
75 82 */
76 83 public function run()
@@ -85,118 +92,132 @@
85 92 )) {
86 93 return;
87 94 }
88 95
89 - $migrations = $this->migrationRegister->getMigrations();
96 + if ( ! class_exists('WP_Upgrader')) {
97 + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
98 + }
90 99
91 - foreach ($migrations as $migrationClass) {
92 - $migrationId = $migrationClass::id();
100 + // Migrations run on every request, so without this a slow one (an ALTER TABLE over millions of
101 + // rows) starts again in every request that arrives while it is still running.
102 + if ( ! WP_Upgrader::create_lock(self::LOCK_NAME)) {
103 + return;
104 + }
93 105
94 - if (in_array($migrationId, $this->completedMigrations, true)) {
95 - continue;
96 - }
106 + try {
107 + $migrations = $this->migrationRegister->getMigrations();
97 108
98 - $migrationLog = $this->migrationLogFactory->make($migrationId);
109 + foreach ($migrations as $migrationClass) {
110 + $migrationId = $migrationClass::id();
99 111
100 - try {
101 - /**
102 - * @var Migration|BatchMigration $migration
103 - */
104 - $migration = give($migrationClass);
112 + if (in_array($migrationId, $this->completedMigrations, true)) {
113 + continue;
114 + }
105 115
106 - if ($migration instanceof BatchMigration) {
107 - $status = (new BatchMigrationRunner($migration))->run();
116 + $migrationLog = $this->migrationLogFactory->make($migrationId);
108 117
109 - if ($status === MigrationLogStatus::RUNNING) {
110 - give()->notices->register_notice(
111 - [
112 - 'id' => $migrationId,
113 - 'description' => esc_html__('GiveWP is running database updates in the background. You will be notified as soon as it completes.',
114 - 'give'),
115 - ]
116 - );
118 + try {
119 + /**
120 + * @var Migration|BatchMigration $migration
121 + */
122 + $migration = give($migrationClass);
117 123
118 - // Update status to RUNNING
119 - if (MigrationLogStatus::RUNNING !== $migrationLog->getStatus()) {
120 - $migrationLog->setStatus(MigrationLogStatus::RUNNING);
121 - $migrationLog->save();
124 + if ($migration instanceof BatchMigration) {
125 + $status = (new BatchMigrationRunner($migration))->run();
126 +
127 + if ($status === MigrationLogStatus::RUNNING) {
128 + give()->notices->register_notice(
129 + [
130 + 'id' => $migrationId,
131 + 'description' => esc_html__('GiveWP is running database updates in the background. You will be notified as soon as it completes.',
132 + 'give'),
133 + ]
134 + );
135 +
136 + // Update status to RUNNING
137 + if (MigrationLogStatus::RUNNING !== $migrationLog->getStatus()) {
138 + $migrationLog->setStatus(MigrationLogStatus::RUNNING);
139 + $migrationLog->save();
140 + }
141 +
142 + break;
122 143 }
123 144
124 - break;
125 - }
145 + if ($status === MigrationLogStatus::INCOMPLETE) {
146 + $listTableLink = sprintf(
147 + '<a href="%s">%s</a>',
148 + admin_url('edit.php?post_type=give_forms&page=give-tools&tab=data'),
149 + esc_html__('Resume update', 'give')
150 + );
126 151
127 - if ($status === MigrationLogStatus::INCOMPLETE) {
128 - $listTableLink = sprintf(
129 - '<a href="%s">%s</a>',
130 - admin_url('edit.php?post_type=give_forms&page=give-tools&tab=data'),
131 - esc_html__('Resume update', 'give')
132 - );
152 + give()->notices->register_notice(
153 + [
154 + 'id' => $migrationId,
155 + 'type' => 'warning',
156 + 'description' => sprintf(
157 + __('Incomplete database update: "%s". %s', 'give'),
158 + $migration::title(),
159 + $listTableLink
160 + ),
161 + ]
162 + );
163 + }
133 164
134 - give()->notices->register_notice(
135 - [
136 - 'id' => $migrationId,
137 - 'type' => 'warning',
138 - 'description' => sprintf(
139 - __('Incomplete database update: "%s". %s', 'give'),
140 - $migration::title(),
141 - $listTableLink
142 - ),
143 - ]
144 - );
165 + $migrationLog->setStatus($status);
166 + } else {
167 + $migration->run();
168 + $migrationLog->setStatus(MigrationLogStatus::SUCCESS);
145 169 }
170 + } catch (Exception $exception) {
171 + DB::rollback();
172 + $migrationLog
173 + ->setStatus(MigrationLogStatus::FAILED)
174 + ->setError([
175 + 'status' => __('Migration failed', 'give'),
176 + 'error' => [
177 + 'message' => $exception->getMessage(),
178 + 'code' => $exception->getCode(),
179 + 'file' => $exception->getFile(),
180 + 'line' => $exception->getLine(),
181 + ],
182 + ]);
146 183
147 - $migrationLog->setStatus($status);
148 - } else {
149 - $migration->run();
150 - $migrationLog->setStatus(MigrationLogStatus::SUCCESS);
184 + give()->notices->register_notice(
185 + [
186 + 'id' => 'migration-failure',
187 + 'description' => sprintf(
188 + '%1$s <a href="https://givewp.com/support/">https://givewp.com/support</a>',
189 + esc_html__(
190 + 'There was a problem running the migrations. Please reach out to GiveWP support for assistance:',
191 + 'give'
192 + )
193 + ),
194 + ]
195 + );
151 196 }
152 - } catch (Exception $exception) {
153 - DB::rollback();
154 - $migrationLog
155 - ->setStatus(MigrationLogStatus::FAILED)
156 - ->setError([
157 - 'status' => __('Migration failed', 'give'),
158 - 'error' => [
159 - 'message' => $exception->getMessage(),
160 - 'code' => $exception->getCode(),
161 - 'file' => $exception->getFile(),
162 - 'line' => $exception->getLine(),
163 - ],
164 - ]);
165 197
166 - give()->notices->register_notice(
167 - [
168 - 'id' => 'migration-failure',
169 - 'description' => sprintf(
170 - '%1$s <a href="https://givewp.com/support/">https://givewp.com/support</a>',
171 - esc_html__(
172 - 'There was a problem running the migrations. Please reach out to GiveWP support for assistance:',
173 - 'give'
174 - )
175 - ),
176 - ]
177 - );
178 - }
198 + try {
199 + $migrationLog->save();
200 + } catch (DatabaseQueryException $e) {
201 + Log::error(
202 + 'Failed to save migration log',
203 + [
204 + 'Error Message' => $e->getMessage(),
205 + 'Query Errors' => $e->getQueryErrors(),
206 + ]
207 + );
208 + }
179 209
180 - try {
181 - $migrationLog->save();
182 - } catch (DatabaseQueryException $e) {
183 - Log::error(
184 - 'Failed to save migration log',
185 - [
186 - 'Error Message' => $e->getMessage(),
187 - 'Query Errors' => $e->getQueryErrors(),
188 - ]
189 - );
190 - }
210 + // Stop Migration Runner if migration has failed
211 + if ($migrationLog->getStatus() === MigrationLogStatus::FAILED) {
212 + break;
213 + }
191 214
192 - // Stop Migration Runner if migration has failed
193 - if ($migrationLog->getStatus() === MigrationLogStatus::FAILED) {
194 - break;
215 + // Commit transaction if successful
216 + DB::commit();
195 217 }
196 -
197 - // Commit transaction if successful
198 - DB::commit();
218 + } finally {
219 + WP_Upgrader::release_lock(self::LOCK_NAME);
199 220 }
200 221 }
201 222
202 223 /**