Skip to content

feat(store/redis): namespace keys per tenant with WithKeyPrefix - #32

Merged
juicycleff merged 1 commit into
mainfrom
feat/redis-key-prefix
Sep 14, 2026
Merged

juicycleff merged 1 commit into
mainfrom
feat/redis-key-prefix

Conversation

@juicycleff

Copy link
Copy Markdown
Contributor

Run two dispatch instances against one Redis today and they share every key under dispatch:*. Each dequeues the other's jobs, sees the other's cron names as duplicates and blocks on the other's leader key. A grove namespace hook can't help because streams, the wake channel and the lease scripts talk to go-redis directly.

This adds redis.WithKeyPrefix. Every key, stream and channel now comes from one keys type on the store, and the tenant segment goes outside the namespace: ws_acme:dispatch:job:. That matches how a tenant's other Redis keys look, so one SCAN pattern finds all of it. Pass an empty prefix (or nothing) and you get the exact old keys, so nothing you already run changes.

On the forge extension you set it as key_prefix in YAML or WithKVKeyPrefix from Go. It only applies on the grove KV path; the grove database path ignores it.

Tests: two prefixed stores on one container must not see each other's jobs, cron names or leadership; an empty prefix reads what an unprefixed store wrote; YAML beats the programmatic value in the merge. The full store/redis integration suite and the extension package pass, golangci-lint is clean.

Tagged v1.6.6.

If you run more than one dispatch instance against the same Redis, they
all write under dispatch:* and start dequeuing each other's jobs, treating
each other's cron names as duplicates and fighting over the leader key.
Nothing outside the store can fix that: streams, the wake channel and the
lease scripts go straight to go-redis, so a grove namespace hook never sees
them.

Every key the store touches now comes from one keys type on the Store.
redis.WithKeyPrefix("ws_acme:") puts the tenant segment outside the
dispatch namespace (ws_acme:dispatch:job:<id>), the same layout a tenant's
other Redis keys use, so one SCAN pattern covers everything it owns. An
empty prefix is byte for byte the old key, so existing deployments keep
their data.

The forge extension reads it as key_prefix in YAML or WithKVKeyPrefix from
Go and passes it through on the grove KV path only. Tests cover job, cron
and leadership isolation between two prefixed stores on one container, the
legacy key shape for an empty prefix, and YAML winning the merge.
@juicycleff
juicycleff merged commit 795bc0e into main Sep 14, 2026
15 checks passed
@juicycleff
juicycleff deleted the feat/redis-key-prefix branch September 14, 2026 22:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant