From 4ce2fac42d29adbc7b9e5d705c38d0ca339c0b41 Mon Sep 17 00:00:00 2001 From: Vladimir Bryzgalov Date: Fri, 17 Apr 2026 22:45:38 +0500 Subject: [PATCH] feat(dispatcher): WP-Cron tick with backoff and retention cleanup --- includes/class-dispatcher.php | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 includes/class-dispatcher.php diff --git a/includes/class-dispatcher.php b/includes/class-dispatcher.php new file mode 100644 index 0000000..2550338 --- /dev/null +++ b/includes/class-dispatcher.php @@ -0,0 +1,72 @@ + 60, + 'display' => 'Раз в минуту (CF7 Spam → TG)', + ]; + return $schedules; + } + + public static function tick(): void + { + if (!Settings::is_configured()) { + return; + } + $items = Queue::fetch_pending(5); + $chat_id = Settings::get_chat_id(); + foreach ($items as $item) { + $payload = json_decode((string)$item->payload_json, true); + if (!is_array($payload) || empty($payload['text'])) { + Queue::mark_failed((int)$item->id, 'Invalid payload JSON', (int)$item->attempts + 1); + continue; + } + try { + TelegramClient::send_message( + $chat_id, + (string)$payload['text'], + isset($payload['reply_markup']) && is_array($payload['reply_markup']) ? $payload['reply_markup'] : null + ); + Queue::mark_sent((int)$item->id); + } catch (TelegramException $e) { + self::handle_failure($item, $e); + } + usleep(100000); // 100ms between sends + } + } + + private static function handle_failure(object $item, TelegramException $e): void + { + $attempts = (int)$item->attempts + 1; + if ($e->is_permanent() || $attempts >= self::MAX_ATTEMPTS) { + Queue::mark_failed((int)$item->id, $e->getMessage(), $attempts); + return; + } + $backoff = self::BACKOFF_SECONDS[$attempts - 1] ?? end(self::BACKOFF_SECONDS); + if ($e->retry_after() > $backoff) { + $backoff = $e->retry_after(); + } + Queue::reschedule((int)$item->id, $attempts, $e->getMessage(), $backoff); + } + + public static function cleanup(): void + { + Queue::cleanup_old_sent(30); + } +}