PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 5.4.3
WooCommerce Square v5.4.3
5.4.3 5.4.2 5.4.1 5.4.0 trunk 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 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.0.8 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.7.0 2.8.0 2.9.0 2.9.1 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.2.0 3.3.0 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.7.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 4.0.0 4.1.0 4.2.0 4.2.1 4.2.2 4.2.3 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.9.0 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.6 4.9.7 4.9.8 4.9.9 5.0.0 5.0.1 5.1.0 5.1.1 5.1.2 5.2.0 5.3.0 5.3.1 5.3.2 5.3.3
woocommerce-square / includes / Sync / Stepped_Job.php
woocommerce-square / includes / Sync Last commit date
Records 3 months ago Catalog_Item.php 9 months ago Helper.php 1 year ago Interval_Polling.php 6 months ago Job.php 2 years ago Manual_Synchronization.php 1 month ago Order_Importer.php 11 months ago Order_Mapper.php 11 months ago Order_Polling.php 11 months ago Product_Import.php 2 months ago Records.php 2 years ago Stepped_Job.php 2 years ago
Stepped_Job.php
336 lines
1 <?php
2 /**
3 * WooCommerce Square
4 *
5 * This source file is subject to the GNU General Public License v3.0
6 * that is bundled with this package in the file license.txt.
7 * It is also available through the world-wide-web at this URL:
8 * http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later
9 * If you did not receive a copy of the license and are unable to
10 * obtain it through the world-wide-web, please send an email
11 * to license@woocommerce.com so we can send you a copy immediately.
12 *
13 * DISCLAIMER
14 *
15 * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16 * versions in the future. If you wish to customize WooCommerce Square for your
17 * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18 *
19 * @author WooCommerce
20 * @copyright Copyright: (c) 2019, Automattic, Inc.
21 * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later
22 */
23
24 namespace WooCommerce\Square\Sync;
25
26 defined( 'ABSPATH' ) || exit;
27
28 /**
29 * Stepped Job abstract.
30 *
31 * Adds multi-step management to the job class.
32 *
33 * @since 2.0.0
34 */
35 abstract class Stepped_Job extends Job {
36
37
38 /**
39 * Executes the next step of this job.
40 *
41 * @since 2.0.0
42 *
43 * @return \stdClass the job object
44 */
45 public function run() {
46
47 parent::run();
48
49 if ( empty( $this->get_attr( 'next_steps' ) ) && empty( $this->get_attr( 'completed_steps' ) ) ) {
50 $this->assign_next_steps();
51 }
52
53 $this->do_next_step();
54
55 return $this->job;
56 }
57
58
59 /**
60 * Assigns the next steps needed for this sync job.
61 *
62 * Adds the next steps to the 'next_steps' attribute.
63 *
64 * @since 2.0.0
65 */
66 abstract protected function assign_next_steps();
67
68
69 /**
70 * Gets the next step in the sync process.
71 *
72 * @since 2.0.0
73 *
74 * @return string|null
75 */
76 protected function get_next_step() {
77
78 $next_steps = $this->get_next_steps();
79
80 return isset( $next_steps[0] ) ? $next_steps[0] : null;
81 }
82
83
84 /**
85 * Gets the next steps for the sync process.
86 *
87 * @since 2.0.0
88 *
89 * @return string[]
90 */
91 protected function get_next_steps() {
92
93 return $this->get_attr( 'next_steps' );
94 }
95
96
97 /**
98 * Performs the next step in the sync process.
99 *
100 * @since 2.0.0
101 */
102 protected function do_next_step() {
103 $max_retry = 3; // Maximum number of retries for rate limit errors.
104 $retry = $this->get_attr( 'retry', 0 ); // Number of retries for rate limit errors.
105
106 $next_step = $this->get_next_step();
107
108 if ( is_callable( array( $this, $next_step ) ) ) {
109
110 $this->start_step_cycle( $next_step );
111
112 try {
113
114 $this->$next_step();
115 $this->complete_step_cycle( $next_step );
116 $this->set_attr( 'retry', 0 ); // Reset retry count to 0 after successful step cycle.
117 } catch ( \Exception $exception ) {
118 $error_message = $exception->getMessage();
119 // If sync fail with rate limit error, retry the sync process after few seconds. (retry upto 3 times)
120 if ( false !== strpos( $error_message, 'RATE_LIMITED' ) && $retry < $max_retry ) {
121 wc_square()->log( 'Rate limit error detected, pausing sync process for few secs...' );
122 $this->set_attr( 'retry', $retry + 1 );
123 return;
124 }
125
126 $this->complete_step_cycle( $next_step, false, $exception->getMessage() );
127 $this->fail( $exception->getMessage() );
128 return;
129 }
130 }
131
132 if ( ! $this->get_next_step() ) {
133
134 $this->complete();
135 }
136 }
137
138
139 /**
140 * Records the beginning of a new step cycle, meaning a new loop on the job for a given step.
141 *
142 * @since 2.0.0
143 *
144 * @param string $step_name the step name
145 */
146 protected function start_step_cycle( $step_name ) {
147
148 $current_step_cycle = array(
149 'step_name' => $step_name,
150 'start_time' => microtime( true ),
151 );
152
153 wc_square()->log( "Starting step cycle: $step_name" );
154
155 $this->set_attr( 'current_step_cycle', $current_step_cycle );
156 }
157
158
159 /**
160 * Records the completion of a step cycle.
161 *
162 * @since 2.0.0
163 *
164 * @param string $step_name the step name
165 * @param bool $is_successful (optional) whether the step completion is from a success or not
166 * @param string $error_message (optional) error message to include with failed step log
167 */
168 protected function complete_step_cycle( $step_name, $is_successful = true, $error_message = '' ) {
169
170 $current_step_cycle = $this->get_attr( 'current_step_cycle', array() );
171
172 if ( ! empty( $current_step_cycle ) ) {
173
174 $current_step_cycle['end_time'] = microtime( true );
175 $current_step_cycle['runtime'] = number_format( $current_step_cycle['end_time'] - $current_step_cycle['start_time'], 2 ) . 's';
176 $current_step_cycle['success'] = true === $is_successful;
177
178 if ( true === $is_successful ) {
179
180 wc_square()->log( "Completed step cycle: $step_name ({$current_step_cycle['runtime']})" );
181
182 } else {
183
184 wc_square()->log( "Failed step cycle: $step_name ({$current_step_cycle['runtime']}) - $error_message" );
185 }
186
187 $completed_cycles = $this->get_attr( 'completed_step_cycles', array() );
188 $completed_cycles[] = $current_step_cycle;
189 $this->set_attr( 'completed_step_cycles', $completed_cycles );
190 }
191 }
192
193
194 /**
195 * Completes the specified step (if it's the next step).
196 *
197 * @since 2.0.0
198 *
199 * @param string $step_name
200 */
201 protected function complete_step( $step_name ) {
202
203 $next_steps = $this->get_next_steps();
204
205 if ( isset( $next_steps[0] ) && $step_name === $next_steps[0] ) {
206
207 $this->add_completed_step( $step_name );
208 array_shift( $next_steps );
209 $this->set_attr( 'next_steps', $next_steps );
210 }
211 }
212
213
214 /**
215 * Adds a step to the completed steps array.
216 *
217 * @since 2.0.0
218 *
219 * @param string $step_name
220 */
221 protected function add_completed_step( $step_name ) {
222
223 if ( empty( $step_name ) ) {
224 return;
225 }
226
227 $completed_steps = $this->get_attr( 'completed_steps', array() );
228
229 $completed_steps[] = array(
230 'name' => $step_name,
231 'completion_time' => current_time( 'mysql' ),
232 );
233
234 $this->set_attr( 'completed_steps', $completed_steps );
235
236 $update_data = $this->get_step_update_data( $step_name );
237
238 wc_square()->log( 'Completed job step: ' . $step_name . $update_data );
239 }
240
241 /**
242 * Get step update data like count of synced products or categories.
243 *
244 * @param string $step_name Step name.
245 * @return string
246 */
247 protected function get_step_update_data( $step_name ) {
248 $update_data = '';
249 $count = $this->get_attr( $step_name . '_count', 0 );
250 switch ( $step_name ) {
251 // Product Import.
252 case 'import_products':
253 $imported = count( $this->get_attr( 'processed_product_ids', array() ) );
254 $updated = count( $this->get_attr( 'updated_product_ids', array() ) );
255 $skipped = count( $this->get_attr( 'skipped_products', array() ) );
256 $update_data = sprintf( ' (Imported products: %d, Updated products: %d, Skipped products: %d)', $imported, $updated, $skipped );
257 break;
258
259 case 'import_inventory':
260 $update_data = sprintf( ' (Synced products: %d)', $count );
261 break;
262
263 // Manual Sync.
264 case 'validate_products':
265 $count = count( $this->get_attr( 'validated_product_ids', array() ) );
266 $update_data = sprintf( ' (Validated products: %d)', $count );
267 break;
268
269 case 'extract_category_ids':
270 $count = count( $this->get_attr( 'category_ids', array() ) );
271 $update_data = sprintf( ' (Extracted categories: %d)', $count );
272 break;
273
274 case 'refresh_category_mappings':
275 $mapped_cat = count( $this->get_attr( 'mapped_categories', array() ) );
276 $unmapped_cat = count( $this->get_attr( 'unmapped_categories', array() ) );
277 $update_data = sprintf( ' (Mapped categories: %d, Unmapped categories: %d)', $mapped_cat, $unmapped_cat );
278 break;
279
280 case 'query_unmapped_categories':
281 $mapped_cat = count( $this->get_attr( 'mapped_categories', array() ) );
282 $update_data = sprintf( ' (Total mapped categories: %d)', $mapped_cat );
283 break;
284
285 case 'upsert_categories':
286 $count = count( $this->get_attr( 'category_ids', array() ) );
287 $update_data = sprintf( ' (Upserted categories: %d)', $count );
288 break;
289
290 case 'update_matched_products':
291 $count = count( $this->get_attr( 'processed_product_ids', array() ) );
292 $update_data = sprintf( ' (Synced matched products: %d)', $count );
293 break;
294
295 case 'search_matched_products':
296 case 'square_sor_sync':
297 $count = count( $this->get_attr( 'processed_product_ids', array() ) );
298 $update_data = sprintf( ' (Synced products: %d)', $count );
299 break;
300
301 case 'upsert_new_products':
302 $count = count( $this->get_attr( 'inventory_push_product_ids', array() ) );
303 $update_data = sprintf( ' (Newly upserted products: %d)', $count );
304 break;
305
306 case 'push_inventory':
307 $update_data = sprintf( ' (Synced products: %d)', $count );
308 break;
309
310 case 'pull_inventory':
311 $count = count( $this->get_attr( 'processed_square_variation_ids', array() ) );
312 $update_data = sprintf( ' (Synced products: %d)', $count );
313 break;
314
315 // Interval Polling.
316 case 'update_category_data':
317 $update_data = sprintf( ' (Updated categories: %d)', $count );
318 break;
319
320 case 'update_product_data':
321 $update_data = sprintf( ' (Updated products: %d)', $count );
322 break;
323
324 case 'update_inventory_counts':
325 $update_data = sprintf( ' (Synced products: %d)', $count );
326 break;
327
328 default:
329 break;
330 }
331
332 return $update_data;
333 }
334
335 }
336