Short answer: treat local calendar time as schedule data, store the next due instant in UTC, and let a short dispatcher feed a rate-limited worker pool. For an edtech reminder service serving US and EU users, this keeps daily and weekly notifications aligned through DST while making queue pressure and duplicate delivery measurable.

The scheduler is not the delivery system. It is a checkpoint that asks, “what is due now?” That distinction matters when a class enrollment campaign creates more reminders than the notification provider can accept. A cron tick can wake the dispatcher, but it cannot be the record of what users were promised.

The failure I care about is the quiet one. A batch of 8,000 due reminders arrives after an enrollment deadline, the worker pool can send only 120 notifications per minute, and the dispatcher keeps treating queue acceptance as success. By the time an operator notices that the oldest due item is 40 minutes late, retries have mixed with fresh work, two regions are competing for the same users, and the logs show API request IDs instead of a schedule occurrence. The repair is a state model: one durable cursor per reminder, one occurrence ID per intended delivery, a bounded claim size, and a ledger entry at the side-effect boundary. That model does not make the provider faster. It does make lateness visible, stops the dispatcher from creating an unbounded second backlog, and gives the on-call engineer a finite set of records to reconcile.