Summary
Stream.unquarantine XRANGEs the entire quarantine stream into process memory and replays it as one atomic MULTI (src/stream.js:502-524 in v0.7.0). Quarantines can hold weeks of updates — we have had multi-GB quarantine streams in production — so restoring one either OOMs the server process or stalls Redis for the duration of a single giant EXEC.
Suggested fix (running in production, offered as a PR)
Read and re-inject in bounded batches (we use 1,000 entries / 8 MB per EXEC), deleting the quarantine key only after the final batch:
- memory and per-
EXEC work become O(batch);
- a crash between batches leaves the quarantine key intact and some entries duplicated in the live stream — safe, because Yjs updates and awareness frames are idempotent under re-application, so the operation is simply re-runnable;
- v0.7.0's
auth:check:v1 drop-on-replay filter is preserved inside the loop.
Return value note: ours returns the count of entries walked (matching current behavior) rather than entries re-injected.
Summary
Stream.unquarantineXRANGEs the entire quarantine stream into process memory and replays it as one atomicMULTI(src/stream.js:502-524 in v0.7.0). Quarantines can hold weeks of updates — we have had multi-GB quarantine streams in production — so restoring one either OOMs the server process or stalls Redis for the duration of a single giantEXEC.Suggested fix (running in production, offered as a PR)
Read and re-inject in bounded batches (we use 1,000 entries / 8 MB per
EXEC), deleting the quarantine key only after the final batch:EXECwork become O(batch);auth:check:v1drop-on-replay filter is preserved inside the loop.Return value note: ours returns the count of entries walked (matching current behavior) rather than entries re-injected.