Skip to content

Commit f83af6e

Browse files
committed
docs(realtime): align seed comments with the atomic-append correctness model
Greptile flagged lingering doc drift: the module + shouldSeed comments still credited the seed lock + empty-stream check as the split-brain fix. Reframe them so the atomic seedIfEmpty is the exactly-once guarantee and shouldSeed is an efficiency gate only.
1 parent ced03b3 commit f83af6e

1 file changed

Lines changed: 13 additions & 8 deletions

File tree

apps/realtime/src/handlers/file-doc-store.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
* opens a file, so a late-joining task (the normal case under autoscaling) loads the current shared
2323
* state before its first client syncs. Catch-up + tail are seamless: the tailer resumes from the
2424
* exact id catch-up stopped at.
25-
* - {@link shouldSeed} coordinates the one-time seed with a Redis lock AND an empty-stream check, so
26-
* exactly one task ever writes the seed cluster-wide (the fix for split-brain).
25+
* - The one-time seed is written via the atomic {@link seedIfEmpty} (append-iff-empty in one Redis
26+
* step), so exactly one task ever writes the seed cluster-wide (the fix for split-brain) — even if two
27+
* tasks race. {@link shouldSeed} is a Redis lock + empty-stream check layered on top ONLY as an
28+
* efficiency gate (so tasks don't all run the seed fetch); correctness does not depend on it.
2729
*
2830
* When `REDIS_URL` is unset (single-pod dev) the store is DISABLED and every method degrades to the
2931
* relay's original single-replica behavior: seed locally, no stream, no tailer.
@@ -364,17 +366,20 @@ export class FileDocStore {
364366
}
365367

366368
/**
367-
* Decide whether THIS task should build and write the file's one-time seed. Returns a lock TOKEN only
368-
* when the shared stream is genuinely empty AND this task wins the seed lock — so exactly one task
369-
* across the cluster ever seeds a file, even if several open it at once (the fix for split-brain
370-
* seeding). `null` otherwise. Release the token with {@link releaseSeedLock}. Disabled → always a
371-
* token (single-replica: seed locally).
369+
* Decide whether THIS task should run the (expensive) seed fetch + write for a file. Returns a lock
370+
* TOKEN when this task wins the seed lock and the stream still looks empty; `null` otherwise. This is an
371+
* EFFICIENCY gate — it stops every task that opens the file at once from each fetching the seed. It does
372+
* NOT by itself guarantee a single seed: exactly-once is enforced by the atomic {@link seedIfEmpty} the
373+
* token-holder then calls (the split-brain guard), so a lock that expires mid-seed cannot cause a
374+
* double-seed. Release the token with {@link releaseSeedLock}. Disabled → always a token (single-replica:
375+
* seed locally).
372376
*/
373377
async shouldSeed(name: string): Promise<string | null> {
374378
const token = await this.acquireLock(`${SEED_LOCK_PREFIX}${name}`, SEED_LOCK_TTL_MS)
375379
if (!token || token === DISABLED_LOCK_TOKEN) return token
376380
// The lock could be free yet the stream already seeded (a prior holder seeded then its lock
377-
// expired). Re-check under the lock so we never write a SECOND seed on top of an existing one.
381+
// expired). Re-check so we skip the redundant seed fetch — the atomic seedIfEmpty would no-op anyway,
382+
// but this avoids the wasted app round-trip.
378383
if (await this.streamHasContent(name)) {
379384
await this.releaseSeedLock(name, token)
380385
return null

0 commit comments

Comments
 (0)