Deliver scheduled cluster messages at their deadline instead of the next poll#1
Draft
sbking wants to merge 4 commits into
Draft
Deliver scheduled cluster messages at their deadline instead of the next poll#1sbking wants to merge 4 commits into
sbking wants to merge 4 commits into
Conversation
sbking
force-pushed
the
feat/cluster-deliver-at-rebuild
branch
from
July 17, 2026 06:46
cf081fe to
6e63cbb
Compare
added 2 commits
July 17, 2026 02:14
The NVARCHAR literals cause SQL Server to convert the indexed VARCHAR `shard_id` column, preventing the per-shard index seek.
Shard identifiers now reach the nextDeliverAt queries as bound parameters in all three dialect branches, with SQL Server keeping its VARCHAR cast. The storage read loop discovers the next scheduled deadline before reading due messages, so a deadline crossing between the two reads arms a wake instead of waiting for the next poll interval. Regression tests cover a quote-bearing shard group and a deadline that lands between the reads.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Messages saved with a future
deliverAtare only discovered by the periodic storage poll, so a scheduled message can be delivered up to a full poll interval after its deadline.MessageStorage.nextDeliverAtoperation that returns the earliest future scheduled delivery time for a set of shards, with memory and SQL driver implementationsShardingre-arms a single replaceable timer for that deadline; when it fires, it runs the existing storage read pathnextDeliverAtfails, the error is logged at debug level and delivery falls back to the existing pollnextDeliverAtagree whendeliverAtis zeroPostgreSQL and SQLite answer the query with
MIN(deliver_at)over a partial index on(shard_id, deliver_at)filtered to unprocessed scheduled rows. MySQL and SQL Server have no partial indexes, so they seek per shard (correlated scalar subquery andCROSS APPLY ... TOP 1) over a plain(shard_id, processed, deliver_at, last_read)index, which stays flat as processed rows accumulate. Migration0003_deliver_at_indexcreates the index idempotently on all four dialects.Local container benchmarks used 1 million message rows, 300 assigned shards, and roughly 200 to 180,000 pending scheduled messages. With the selected per-dialect queries and indexes, the deadline lookup stayed below 8ms on PostgreSQL, around 4ms on MySQL, below 0.1ms on SQLite, and around 0.7ms on SQL Server. These are warm-cache local measurements; production calls still pay network latency. Synthetic bulk inserts measured roughly 0.3-2μs of additional index work per inserted row.
Testing
nextDeliverAtdegrades to poll-cadence delivery with the read loop still usable;deliverAtat epoch zero across the due boundarypnpm vitest run packages/effect/test/cluster/MessageStorage.test.ts packages/effect/test/cluster/Sharding.test.ts packages/effect/test/cluster/Entity.test.ts(42/42)nextDeliverAtcases pass against PostgreSQL, MySQL, and SQLite (pnpm vitest run packages/platform-node/test/cluster/SqlMessageStorage.test.ts -t nextDeliverAt); the SQL Server leg runs after the rebase over Support SQL Server in cluster SqlMessageStorage Effect-TS/effect#6441 lands its container fixturepnpm checkpnpm lint