Skip to content

perf(runtime-host): list recovery Session headers without the duplicate message decode (#4032) - #4033

Merged
Astro-Han merged 1 commit into
apache:mainfrom
me2seeks:fix/4032-recovery-message-dedupe
Aug 27, 2026
Merged

Astro-Han merged 1 commit into
apache:mainfrom
me2seeks:fix/4032-recovery-message-dedupe

Conversation

@me2seeks

Copy link
Copy Markdown
Contributor

Summary

Refs #4032

prepareHostedExecutionRecovery decoded every recoverable Session's durable messages twice at Host startup: listForRecovery() performs a discarded per-Session readMessagesForRecovery pre-read, and the recovery loop then calls readMessagesForRecovery again per Session (that second read is the one actually used to index and validate admission/message relationships).

This PR lists recovery Session headers via listHeaders() instead, keeping the per-Session readMessagesForRecovery as the single decode. Fail-closed coverage is unchanged: corrupt durable messages still fail startup for the same Sessions, detected at the per-Session read instead of in an upfront sweep.

This is intentionally the conservative first step from #4032. The dominant startup cost — the discarded per-run readEventsForRecovery/readRuntimeEvents validation reads over every run of every Session — is left for maintainer discussion, since skipping it for terminal runs changes the startup-validation contract.

Verification

  • biome format / biome lint clean
  • @maka/runtime-host suite (npm --workspace @maka/runtime-host run test:dist): 1288 tests, 1279 pass, 0 fail, 9 skipped — includes the execution-host-recovery composition tests that exercise prepareHostedExecutionRecovery end to end
  • No new test added: behavior is unchanged by construction (listForRecovery() returns listHeaders() after its discarded pre-read), and the existing recovery suite covers the path. The removed work was a duplicated read whose result no caller consumed.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope: Kimi k3-256k — change, verification, and this PR description. The commit carries a Generated-by trailer.

Checklist

  • Tests cover the change and fail without it (see note above — behavioral no-op covered by the existing recovery suite)
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

Performance-only: identical recovery outcomes and identical startup failure coverage, one less full message decode pass per Host start.

…te message decode

listForRecovery() decodes every recoverable Session's messages and
discards the result before prepareHostedExecutionRecovery re-decodes the
same messages in its per-Session loop, so Host startup paid the message
decode twice per Session. List headers directly; the per-Session
readMessagesForRecovery remains the single fail-closed validation read,
so corrupt durable messages still fail startup for the same Sessions.

Refs apache#4032

Generated-by: Kimi k3-256k

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve.

Verified the claim that behavior is unchanged, since the swap does move when failures surface. listForRecovery() is listHeaders() plus a discarded readMessagesForRecovery sweep over every Session (session-store.ts:754-760), so dropping it means a corrupt Session no longer fails before the loop starts — it now fails on its own iteration, after earlier Sessions have already run rootAdmissions.recoverSession.

That reordering is not observable: recoverSession (root-admission-owner.ts:63-74) only reads durable admissions and populates in-process maps, with no durable write, and a throw out of prepareHostedExecutionRecovery fails Host startup and takes that memory with it. Fail-closed coverage is genuinely the same set of Sessions, just detected one iteration later.

Also confirmed the change leaves no dead code behind: listForRecovery still has real production callers in execution-composition.ts:1436, stream-graph-coordinator.ts:522, and session-manager.ts:5922, so narrowing this one call site rather than removing the method is correct.

I appreciate that the body stops at the conservative step and flags the per-run readEventsForRecovery/readRuntimeEvents sweep as a separate maintainer decision rather than folding a contract change into a perf PR.

AI-assisted review disclosure: Claude Code traced the call graph and the admission-recovery side effects; I verified the store semantics, the caller set, and the failure ordering against current main myself.

@github-actions github-actions Bot added the effort/XS Under 10 readable lines label Aug 27, 2026
@Astro-Han
Astro-Han merged commit 2df11b2 into apache:main Aug 27, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/XS Under 10 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants