feat(dispatcher): WP-Cron tick with backoff and retention cleanup
This commit is contained in:
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Cf7stg;
|
||||||
|
|
||||||
|
final class Dispatcher
|
||||||
|
{
|
||||||
|
private const BACKOFF_SECONDS = [60, 300, 1800, 3600, 3600];
|
||||||
|
private const MAX_ATTEMPTS = 5;
|
||||||
|
|
||||||
|
public static function register_hooks(): void
|
||||||
|
{
|
||||||
|
add_filter('cron_schedules', [__CLASS__, 'register_schedule']);
|
||||||
|
add_action('cf7stg_dispatch', [__CLASS__, 'tick']);
|
||||||
|
add_action('cf7stg_cleanup', [__CLASS__, 'cleanup']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function register_schedule(array $schedules): array
|
||||||
|
{
|
||||||
|
$schedules['cf7stg_every_minute'] = [
|
||||||
|
'interval' => 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user