Files
Siro/backend/bot/cron_sms_requests.php
T

115 lines
5.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* cron_sms_requests.php — شبكة الأمان لمسار الطلب بالرسائل
* ─────────────────────────────────────────────────────────────
* ‏المعالجة الأصلية تتم فورياً داخل webhook_sms/webhook.php، لأن الراكب
* ‏واقف ينتظر رداً ودقيقة تأخير تعني أنه ظنّ الرقم معطّلاً. هذا الكرون
* ‏لا يعالج المسار السعيد إذن — وظيفته ما يسقط منه:
*
* ١. طلبات بقيت 'pending' (فشل شبكي عابر وقت الإنشاء)
* ٢. طلبات عَلِقت في 'dispatching' (مات التنفيذ بين القفل والنتيجة)
* ٣. رحلات لم يقبلها أحد — نخبر الراكب بدل تركه ينتظر بلا خبر
*
* ‏الثالثة هي الأهم: راكب التطبيق يرى الخريطة فيعرف أن البحث جارٍ.
* ‏راكب الرسائل لا يرى شيئاً — صمتنا عنده يساوي عطلاً.
*
* جدولة: كل دقيقة.
* *\/1 * * * * docker compose exec -T php php /var/www/backend/bot/cron_sms_requests.php
*/
require_once __DIR__ . '/../core/bootstrap.php';
require_once __DIR__ . '/../sms/ride_request.php';
// ‏طلب عَلِق في 'dispatching' أطول من هذا يُعتبر ميتاً ويُعاد للطابور.
const SMS_STUCK_MINUTES = 3;
// ‏بعد هذه المدة بلا سائق نخبر الراكب. أقصر من مهلة التطبيق عمداً:
// ‏من ينتظر بلا شاشة يفقد صبره أسرع.
const SMS_NO_DRIVER_MINUTES = 6;
try {
$con = Database::get('main');
} catch (Exception $e) {
fwrite(STDERR, '[sms-cron] DB unavailable: ' . $e->getMessage() . "\n");
exit(1);
}
// ═══════════════════════════════════════════════════════════════
// ١) تحرير العالق
// ═══════════════════════════════════════════════════════════════
$freed = 0;
try {
$st = $con->prepare("
UPDATE sms_ride_requests
SET status = 'pending'
WHERE status = 'dispatching'
AND updated_at < NOW() - INTERVAL " . SMS_STUCK_MINUTES . " MINUTE
");
$st->execute();
$freed = $st->rowCount();
} catch (PDOException $e) {
fwrite(STDERR, '[sms-cron] تعذّر تحرير العالق: ' . $e->getMessage() . "\n");
}
// ═══════════════════════════════════════════════════════════════
// ٢) إعادة محاولة المعلّق
// ═══════════════════════════════════════════════════════════════
$retried = 0;
$created = 0;
try {
$st = $con->query("
SELECT id, sender_norm, passenger_id, start_location, end_location,
start_name, end_name, distance, duration, attempts
FROM sms_ride_requests
WHERE status = 'pending' AND passenger_id IS NOT NULL
ORDER BY id ASC
LIMIT 50
");
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $req) {
$retried++;
if (smsProcessRequest($con, $req)) $created++;
}
} catch (PDOException $e) {
fwrite(STDERR, '[sms-cron] فشل إعادة المحاولة: ' . $e->getMessage() . "\n");
}
// ═══════════════════════════════════════════════════════════════
// ٣) إبلاغ من لم يجد سائقاً
//
// ‏نعتمد على حالة الرحلة نفسها لا على مؤقّت منفصل: ما دامت 'waiting'
// ‏فلا سائق قَبِل. والوسم في fail_reason يمنع تكرار الإبلاغ كل دقيقة.
// ═══════════════════════════════════════════════════════════════
$notified = 0;
try {
$st = $con->prepare("
SELECT s.id, s.sender_norm, s.ride_id
FROM sms_ride_requests s
JOIN ride r ON r.id = s.ride_id
WHERE s.status = 'dispatched'
AND (s.fail_reason IS NULL OR s.fail_reason <> 'no_driver_notified')
AND r.status IN ('waiting', 'wait')
AND s.updated_at < NOW() - INTERVAL " . SMS_NO_DRIVER_MINUTES . " MINUTE
LIMIT 50
");
$st->execute();
foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $row) {
// ‏الوسم أولاً ثم الإرسال: لو انقطع التنفيذ بينهما، أسوأ نتيجة
// ‏رسالة لم تصل — لا رسالة تصل كل دقيقة.
$con->prepare("UPDATE sms_ride_requests SET fail_reason='no_driver_notified' WHERE id=?")
->execute([$row['id']]);
smsEnqueue($con, $row['sender_norm'],
'سيرو: ما زلنا نبحث عن سائق قريب منك. سنرسل لك رسالة فور قبول أحدهم،'
. ' أو أعد إرسال طلبك بعد قليل.',
'no_driver_yet', (string) $row['ride_id']);
$notified++;
}
} catch (PDOException $e) {
fwrite(STDERR, '[sms-cron] تعذّر إبلاغ من بلا سائق: ' . $e->getMessage() . "\n");
}
echo "[sms-cron] حُرِّر {$freed}، أُعيدت محاولة {$retried}، أُنشئ {$created}،"
. " أُبلغ {$notified}\n";