Recurring ticket: a creation failure after claiming a schedule silently and permanently loses that occurrence #88

Closed
opened 2026-09-01 00:08:18 -04:00 by jared · 1 comment
Owner

Severity: Medium

RecurringTicketModel::claimForRun() intentionally advances next_run_at before TicketModel::createTicket() runs (cron/create_recurring_tickets.php) — a deliberate design choice (per an existing code comment) to prevent duplicate-ticket floods if creation fails partway and the cron retries.

Impact of that tradeoff: if createTicket() then fails (DB blip, constraint violation, StatsModel exception, etc.), the catch block only writes a line to stdout/the cron log. next_run_at is already advanced to the next future occurrence, so that specific scheduled occurrence is gone forever with no record anywhere an admin would normally look — no audit_log entry, no Matrix alert, no failure table to review.

Fix: Add a Matrix/error-log alert specifically for this failure path (distinct from normal cron output), or persist failed-claim rows to a small table for manual review/replay, so a silently-skipped recurring ticket doesn't go unnoticed indefinitely.

**Severity:** Medium `RecurringTicketModel::claimForRun()` intentionally advances `next_run_at` **before** `TicketModel::createTicket()` runs (`cron/create_recurring_tickets.php`) — a deliberate design choice (per an existing code comment) to prevent duplicate-ticket floods if creation fails partway and the cron retries. **Impact of that tradeoff:** if `createTicket()` then fails (DB blip, constraint violation, StatsModel exception, etc.), the catch block only writes a line to stdout/the cron log. `next_run_at` is already advanced to the *next future* occurrence, so that specific scheduled occurrence is gone forever with no record anywhere an admin would normally look — no audit_log entry, no Matrix alert, no failure table to review. **Fix:** Add a Matrix/error-log alert specifically for this failure path (distinct from normal cron output), or persist failed-claim rows to a small table for manual review/replay, so a silently-skipped recurring ticket doesn't go unnoticed indefinitely.
jared added the priority/mediumreliability labels 2026-09-08 10:15:49 -04:00
Author
Owner

Fixed and verified (real MariaDB, real running server, real webhook capture, jsdom). Merged to main in commit b6c1709.

Fixed and verified (real MariaDB, real running server, real webhook capture, jsdom). Merged to main in commit b6c1709.
jared closed this issue 2026-09-11 14:49:56 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/tinker_tickets#88