PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.22
ووسلام – همگام سازی ووکامرس و باسلام v1.10.22
1.10.22 1.10.21 1.10.19 1.10.20 1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 All 55 releases
← All changes | JobsRunner.php +48 -12 1.10.20 → 1.10.22 View file →
@@ -10,12 +10,14 @@
10 10 class JobsRunner
11 11 {
12 12 private const ASYNC_ACTION = 'sync_basalam_run_jobs_async';
13 13 private const ASYNC_DISPATCH_LOCK_TRANSIENT = 'sync_basalam_jobs_runner_async_dispatch_lock';
14 + private const ASYNC_IDLE_PROBE_TRANSIENT = 'sync_basalam_jobs_runner_idle_probe_lock';
14 15 // Keep the dispatch lease longer than a normal async batch. Without this,
15 16 // every frontend request can boot another full WordPress AJAX worker while
16 17 // a large product queue is active.
17 18 private const ASYNC_DISPATCH_LOCK_SECONDS = 25;
19 + private const ASYNC_IDLE_PROBE_SECONDS = 5;
18 20 private const ASYNC_TIME_LIMIT_SECONDS = 20;
19 21 private const GLOBAL_RUNNER_LAST_RUN_OPTION = 'sync_basalam_jobs_runner_last_run';
20 22 private const STALE_PROCESSING_TIMEOUT_SECONDS = 120;
21 23
@@ -31,11 +33,10 @@
31 33 $CheckHttpBlockService
32 34 ) {
33 35 add_action('wp_ajax_' . self::ASYNC_ACTION, [$this, 'handleAsyncRequest']);
34 36 add_action('wp_ajax_nopriv_' . self::ASYNC_ACTION, [$this, 'handleAsyncRequest']);
35 - // Probe and dispatch after the response path so normal storefront
36 - // requests never pay for the queue query or loopback HTTP request.
37 - add_action('shutdown', [$this, 'maybeDispatchAsyncRequest'], PHP_INT_MAX);
37 + // Run before later shutdown callbacks can leave an unread mysqli result.
38 + add_action('shutdown', [$this, 'maybeDispatchAsyncRequest'], 2);
38 39 add_action('sync_basalam_job_created', [$this, 'maybeDispatchAsyncRequest'], 10, 0);
39 40
40 41 $this->jobManager = $jobManager;
41 42 $this->jobExecutor = $jobExecutor;
@@ -45,25 +46,60 @@
45 46
46 47 public function maybeDispatchAsyncRequest(): void
47 48 {
48 49 if ($this->isCurrentAsyncRequest()) return;
50 +
51 + if ($this->isShutdownCallback()) {
52 + $this->finishFastCgiResponse();
53 + $this->repairDatabaseConnection();
54 + }
55 +
49 56 if ($this->CheckHttpBlockService->SyncBasalamHttpBlock()) return;
57 + $isNewJob = function_exists('current_filter') && current_filter() === 'sync_basalam_job_created';
58 + if (!$isNewJob && get_transient(self::ASYNC_IDLE_PROBE_TRANSIENT)) return;
50 59 if (get_transient(self::ASYNC_DISPATCH_LOCK_TRANSIENT)) return;
51 60
52 - // Reserve the dispatch lease before probing the queue. This keeps
53 - // concurrent shutdown callbacks from all running the queue query and
54 - // dispatching duplicate async workers.
55 - set_transient(
56 - self::ASYNC_DISPATCH_LOCK_TRANSIENT,
57 - 1,
58 - self::ASYNC_DISPATCH_LOCK_SECONDS
59 - );
60 -
61 61 if (!$this->jobManager->hasPendingOrStaleProcessingJobs(self::STALE_PROCESSING_TIMEOUT_SECONDS)) {
62 + if (!$isNewJob) {
63 + set_transient(self::ASYNC_IDLE_PROBE_TRANSIENT, 1, self::ASYNC_IDLE_PROBE_SECONDS);
64 + }
62 65 return;
63 66 }
64 67
68 + // An empty-queue probe must not block a job created moments later.
69 + // The global database lock still prevents duplicate workers from
70 + // processing the same queue when requests race here.
71 + if (get_transient(self::ASYNC_DISPATCH_LOCK_TRANSIENT)) return;
72 + set_transient(self::ASYNC_DISPATCH_LOCK_TRANSIENT, 1, self::ASYNC_DISPATCH_LOCK_SECONDS);
73 +
65 74 $this->dispatchAsyncRequest();
75 + }
76 +
77 + private function isShutdownCallback(): bool
78 + {
79 + return function_exists('current_filter') && current_filter() === 'shutdown';
80 + }
81 +
82 + private function finishFastCgiResponse(): void
83 + {
84 + if (function_exists('fastcgi_finish_request')) {
85 + fastcgi_finish_request();
86 + }
87 + }
88 +
89 + private function repairDatabaseConnection(): void
90 + {
91 + global $wpdb;
92 +
93 + if (!isset($wpdb) || !is_object($wpdb)) return;
94 +
95 + if (method_exists($wpdb, 'flush')) {
96 + $wpdb->flush();
97 + }
98 +
99 + if (method_exists($wpdb, 'check_connection')) {
100 + $wpdb->check_connection(false);
101 + }
66 102 }
67 103
68 104 public function handleAsyncRequest(): void
69 105 {