Why Your Recurring Invoice Didn't Fire: An Engineering Post-Mortem
I was brought in to audit a freelance tool's recurring billing module. The complaint was consistent: invoices missed their window when the laptop slept or the app wasn't open. The root cause wasn't the code. It was the scheduling model.
Most SaaS platforms rely on timestamp-based cron jobs or background workers. Server pool saturated at 1:59 AM? No invoice. Timezone misconfigured? Fires a day early. Client billing date updated? The job queue drops the event. Good luck.
Offline desktop apps make it worse. Legacy tools check the date on launch. Laptop closed on the 1st, opened on the 5th? The app generates a late invoice with today's timestamp. You look unprofessional. The client notices.
I wasn't going to ship that architecture.
State Reconciliation Over Point-in-Time Execution
The fix wasn't a better cron job. It was a paradigm shift: stop asking what time it is. Ask what state the invoice is in.
LockMargin's recurring engine queries the SQLite database on launch or via a lightweight tokio background task. It filters for items where next_due_date <= today and status is active. If it finds one, it generates the invoice, updates next_due_date, and writes an immutable audit log. No floods. No missed windows. Just the next correct action.
Laptop closed for a week? The engine wakes up, sees five overdue dates, and fires exactly one invoice — the one that was due yesterday. Tomorrow, it fires the next. Idempotent. Deterministic. Offline-safe.
The Rust Implementation Reality
sqlx + tokio + calendar math = two weeks of fighting DST transitions, leap years, and custom cycles like "the last Friday of the month." NaiveDate doesn't care about your feelings. Timezone handling in Rust is explicit, which is good, but it forces you to handle every edge case upfront.
We didn't abstract it away. We exposed it. The engine doesn't guess. It calculates. If the condition is met, it executes. If not, it waits. No magic. No server dependency. Just local state reconciliation.
The difference isn't desktop versus web. It's state-driven scheduling versus timestamp execution. One survives offline gaps. The other doesn't.