Problem
stream.js uses taskDebounce as the xAutoClaim min-idle when claiming tasks:
const reclaimedTasks = await this.redis.xAutoClaim(this.workerStreamName, this.workerGroupName, this.consumername, this.taskDebounce, '0', { COUNT: count })
taskDebounce is fundamentally a scheduling knob — how long a room's task waits after activity before compaction runs. Deployments tune it large to batch compaction work (we run 30 minutes in production to keep worker load sane on large docs).
But because the same value is the reclaim min-idle, it also becomes the failure-recovery latency: when a worker dies ungracefully (OOM, node crash, SIGKILL), its claimed task — lease renewals stopped — sits unclaimed for a full taskDebounce before any surviving worker may pick it up. With a 30-minute debounce, one worker crash means that document's persistence stalls for up to 30 minutes while its edits accumulate only in Redis. The blast radius of Redis loss during that window is exactly the unpersisted backlog this project's quarantine machinery exists to guard.
stopWorker()'s doc comment acknowledges the coupling ("they go stale and are reclaimed by another worker after redis.taskDebounce").
Proposal
Add a separate redis.taskTimeout (reclaim min-idle) defaulting to taskDebounce for compatibility:
claimTasks uses taskTimeout as the xAutoClaim min-idle.
_renewLeases renews at a cadence safely below taskTimeout (today it presumably tracks taskDebounce; the renewal interval and the reclaim idle need to be related to each other, not to the scheduling debounce).
- Constraint check at config time: renewal interval < taskTimeout, so live tasks are never reclaimed out from under a healthy worker.
That lets a deployment run taskDebounce: 30min for scheduling while keeping dead-worker recovery at, say, 60–120s.
Context
@y/hub 0.7.0. Related operational context: we just added graceful SIGTERM draining on our side (stop claiming + wait for in-flight tasks) so routine rollouts don't strand tasks — this issue is about the remaining ungraceful-kill window that only an upstream knob can shrink.
Problem
stream.jsusestaskDebounceas thexAutoClaimmin-idle when claiming tasks:taskDebounceis fundamentally a scheduling knob — how long a room's task waits after activity before compaction runs. Deployments tune it large to batch compaction work (we run 30 minutes in production to keep worker load sane on large docs).But because the same value is the reclaim min-idle, it also becomes the failure-recovery latency: when a worker dies ungracefully (OOM, node crash, SIGKILL), its claimed task — lease renewals stopped — sits unclaimed for a full
taskDebouncebefore any surviving worker may pick it up. With a 30-minute debounce, one worker crash means that document's persistence stalls for up to 30 minutes while its edits accumulate only in Redis. The blast radius of Redis loss during that window is exactly the unpersisted backlog this project's quarantine machinery exists to guard.stopWorker()'s doc comment acknowledges the coupling ("they go stale and are reclaimed by another worker afterredis.taskDebounce").Proposal
Add a separate
redis.taskTimeout(reclaim min-idle) defaulting totaskDebouncefor compatibility:claimTasksusestaskTimeoutas thexAutoClaimmin-idle._renewLeasesrenews at a cadence safely belowtaskTimeout(today it presumably trackstaskDebounce; the renewal interval and the reclaim idle need to be related to each other, not to the scheduling debounce).That lets a deployment run
taskDebounce: 30minfor scheduling while keeping dead-worker recovery at, say, 60–120s.Context
@y/hub 0.7.0. Related operational context: we just added graceful SIGTERM draining on our side (stop claiming + wait for in-flight tasks) so routine rollouts don't strand tasks — this issue is about the remaining ungraceful-kill window that only an upstream knob can shrink.