PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.22
ووسلام – همگام سازی ووکامرس و باسلام v1.10.22
1.10.23 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 All 56 releases
← All changes | JobsRunner.php +47 -11 1.10.15 → 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 - // Keep database work out of shutdown, where another callback may have
36 - // left the shared mysqli connection with an unread result set.
37 - add_action('init', [$this, 'maybeDispatchAsyncRequest'], 10, 0);
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;
@@ -44,26 +45,61 @@
44 45 }
45 46
46 47 public function maybeDispatchAsyncRequest(): void
47 48 {
48 - // Retain a guard for third-party callers that may still invoke this
49 - // method during shutdown even though no shutdown hook is registered.
50 - if (function_exists('did_action') && did_action('shutdown')) return;
51 49 if ($this->isCurrentAsyncRequest()) return;
50 +
51 + if ($this->isShutdownCallback()) {
52 + $this->finishFastCgiResponse();
53 + $this->repairDatabaseConnection();
54 + }
55 +
52 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;
53 59 if (get_transient(self::ASYNC_DISPATCH_LOCK_TRANSIENT)) return;
54 60
55 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 + }
56 65 return;
57 66 }
58 67
59 - set_transient(
60 - self::ASYNC_DISPATCH_LOCK_TRANSIENT,
61 - 1,
62 - self::ASYNC_DISPATCH_LOCK_SECONDS
63 - );
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);
64 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 {