From eb1f167fa455fd84e4beb95feb7c6bb336a95e3e Mon Sep 17 00:00:00 2001 From: _Kerman Date: Thu, 20 Aug 2026 17:14:05 +0800 Subject: [PATCH] refactor(session-projection-cache): restore the base method order Keep the base class's relative method order (write before coldSnapshot) so the diff against the base shows the cold-read methods as a pure insertion instead of a reorder of existing methods. --- .../session-projection-cache/src/index.ts | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/session/session-projection-cache/src/index.ts b/packages/session/session-projection-cache/src/index.ts index c91bb5b304..8845d9a6d3 100644 --- a/packages/session/session-projection-cache/src/index.ts +++ b/packages/session/session-projection-cache/src/index.ts @@ -133,28 +133,6 @@ export class SessionProjectionCache extends Service { return { asOfSeq, values } } - /** - * Cold-read one session's projections from its complete log. Each unit is - * seeded from the identity-checked cached rows — the registry skips `apply` - * for the already-folded prefix (events at or below the row's `seq`) — and - * the refreshed checkpoint is written back (fail-soft, fire-and-forget), so - * the first cold read creates the cache row and later ones seed from it. - * The caller supplies the complete log in seq order: this service never - * consults the persistence layer. - * @param meta - the stored session header (identity witness). - * @param events - the session's complete log, in seq order. - * @returns the projection cut at the log end. - */ - coldSnapshot(meta: SessionHeader, events: readonly SessionEvent[]): ProjectionSnapshot { - const restored = this.ctx.sessionProjections.restore(this.recordFor(meta.id, identityOf(meta))?.rows ?? {}, events, 0) - // Refresh the row so the next cold read seeds from it; fail-soft and - // fire-and-forget — a failed write-back only costs a longer tail replay. - void this.put(meta.id, identityOf(meta), restored.checkpoint).catch((error: unknown) => { - this.ctx.logger.warn(`session projection cache: cold-read write-back for "${meta.id}" failed (cache stays stale): ${String(error)}`) - }) - return restored.snapshot - } - /** * Durably checkpoint one live session NOW (both mandatory points call * this; tests and carriers may too). The registry cut is snapshotted at @@ -178,6 +156,29 @@ export class SessionProjectionCache extends Service { await this.put(session.id, identityOf(session.header), rows) } + /** + * Cold-read one session's projections from its complete log. Each unit is + * seeded from the identity-checked cached rows — the registry skips `apply` + * for the already-folded prefix (events at or below the row's `seq`) — and + * the refreshed checkpoint is written back (fail-soft, fire-and-forget), so + * the first cold read creates the cache row and later ones seed from it. + * The caller supplies the complete log in seq order: this service never + * consults the persistence layer. + * @param meta - the stored session header (identity witness). + * @param events - the session's complete log, in seq order. + * @returns the projection cut at the log end. + */ + coldSnapshot(meta: SessionHeader, events: readonly SessionEvent[]): ProjectionSnapshot { + const restored = this.ctx.sessionProjections.restore(this.recordFor(meta.id, identityOf(meta))?.rows ?? {}, events, 0) + // Refresh the row so the next cold read seeds from it; fail-soft and + // fire-and-forget — a failed write-back only costs a longer tail replay. + void this.put(meta.id, identityOf(meta), restored.checkpoint).catch((error: unknown) => { + this.ctx.logger.warn(`session projection cache: cold-read write-back for "${meta.id}" failed (cache stays stale): ${String(error)}`) + }) + return restored.snapshot + } + + // --- write-behind (throttle + mandatory points) --- private installWritePath(): void {