Repository navigation
Let Redis queue users choose LIST or ZSET storage - #1447
Open
danielgerlag wants to merge 4 commits into
Open
danielgerlag wants to merge 4 commits into
danielgerlag wants to merge 4 commits into
Conversation
danielgerlag
marked this pull request as ready for review
September 8, 2026 20:35
cursor
Bot
force-pushed
the
cursor/redis-queue-zset-8044
branch
from
September 14, 2026 15:24
9cb6d38 to
5843671
Compare
Keep LIST as the default with atomic Lua uniqueness so existing deployments can roll forward. SortedSet remains an opt-in that migrates leftover LIST keys on Start(). Do not mix modes on the same prefix. Preserve WorkflowOptions Enable* queue flags. Co-authored-by: Daniel Gerlag <danielgerlag@users.noreply.github.com>
cursor
Bot
force-pushed
the
cursor/redis-queue-zset-8044
branch
from
September 14, 2026 15:24
5843671 to
50be521
Compare
Add a Redis providers page covering UseRedisQueues defaults, the SortedSet opt-in, key names, and the do-not-mix cutover rule, and link it from nav, clusters, and persistence. Co-authored-by: Daniel Gerlag <danielgerlag@users.noreply.github.com>
A missing blank line before the UseRedis* bullets collapsed them into a single paragraph on the MkDocs site. Co-authored-by: Daniel Gerlag <danielgerlag@users.noreply.github.com>
Collaborator
|
Review: Approve (nits only)
Nits (non-blocking, docs follow-up):
Optional later: monotonic ZSET score if strict FIFO is required. |
SortedSet needs ZADD NX (Redis 3.0.2+), not Lua 2.6+ alone. Same-µs TIME scores order lexicographically by id. Start() migrate loads the whole LIST in one EVAL. Co-authored-by: Daniel Gerlag <danielgerlag@users.noreply.github.com>
This branch has not been deployed
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.
Describe the change
UseRedisQueuesnow takes an explicit storage implementation so Redis queue users can choose LIST vs ZSET. This is not a forced LIST→ZSET cutover.RedisQueueStorage.List(default): same{prefix}-workflows|events|indexLIST keys, with the atomic Lua uniqueness from Harden Redis queue uniqueness with atomic Lua enqueue #1446 (LINSERT/RPUSH/LREMin oneEVAL). Dequeue staysLPOP. Rolling-upgrade friendly with existing LIST deployments.RedisQueueStorage.SortedSet: opt-in ZSET path (ZADD NX+ RedisTIMEscores; dequeue is LuaZRANGE+ZREM).Start()migrates leftover LIST items only when this mode is selected.IQueueProvideris unchanged.WorkflowOptions.EnableWorkflows|EnableEvents|EnableIndexesstill gate which queues are used (#1154). Issue #1417 /QueueConsumer._secondPassesis not addressed here.#1446’s LIST Lua uniqueness is folded in, so that PR is unnecessary if this lands.
Describe your implementation or design
Start()List(default)LPOPSortedSetZADD NX+TIMEµsZRANGE 0 0+ZREMEVAL(first occurrence kept)Queue key names are unchanged. Do not mix modes on the same key prefix — Redis cannot store LIST and ZSET on one key (
WRONGTYPE), and mixed hosts will split or lose work.Rejected: forcing ZSET as the only path (hard cutover for every existing LIST deployment).
Rebased onto current
masterso theWorkflowOptionsconstructor / enable-flag path from #1154 is preserved.Tests
RedisQueueProviderListFixtureandRedisQueueProviderSortedSetFixtureshare uniqueness/FIFO coverage, then add mode-specific cases:LPOP;Start()does not migrate LIST→ZSETStart()migrates a leftover LIST (dedupes, keeps FIFO, new enqueues go behind); existing ZSET is left untouchedLocal: 23/23 passed against Redis 7.0.15 after the master rebase (
WORKFLOWCORE_REDIS=localhost:6379,dotnet test test/WorkflowCore.Tests.Redis --filter FullyQualifiedName~RedisQueueProvider).Breaking change
No for the default.
UseRedisQueues(connectionString, prefix)stays LIST.The remaining break applies only when opting into
RedisQueueStorage.SortedSet: those hosts change the Redis value type on the existing queue keys from LIST to ZSET. Coordinated cutover for that prefix (stop every host, deploy with SortedSet, start;Start()migrates leftover LIST items). A flush is not required unless you choose to drop in-flight work.Compatibility
List): same keys, same LIST type, uniqueness now actually atomic. Existing LIST keys (including those that already contain duplicates) need no migration. Rolling upgrades with older LIST hosts share the same LIST; an old process can still race its own multi-command sequence until every node is upgraded.SortedSet): Do not mix withList(or older LIST-only hosts) on the same prefix. Mixed processes willWRONGTYPEor ignore each other's pending work.TIMEin microseconds. If two enqueues share the same µs, Redis orders those members lexicographically by id — so SortedSet FIFO is slightly weaker than LIST under burst enqueue. After pop, a laterZADDof the same id gets a new (later) score.Listis Lua 2.6+ / LINSERT 2.2+.SortedSet/ZADD NXrequires Redis 3.0.2+ (Lua 2.6+ is not enough). SortedSet dequeue does not call nativeZPOPMIN(Redis 5+).Start()loads the whole LIST into one LuaEVAL(can briefly block Redis on a huge backlog); acceptable for a one-time cutover.IQueueProvider/ other providers: unchanged.Docs
The main MkDocs site now has a Redis providers page (
docs/redis.md) covering List vs SortedSet, linked from nav, multi-node clusters, and persistence. Full detail remains in the Redis provider README.Additional context
Supersedes #1446 (LIST Lua uniqueness is included here). Prefer this PR if both are open.
Queue key format is unchanged:
{prefix}-workflows,{prefix}-events,{prefix}-index.