perf(runtime): reduce database-bound turn latency - #670
Conversation
XuPeng-SH
left a comment
There was a problem hiding this comment.
结论:当前不建议合并,请先修复以下问题。
- [P1] 流式执行失去 terminal ownership 后仍会写派生状态
crates/runtime/src/server/run/lifecycle/mod.rs 的 terminal projection block(约 L16629-L16684)没有受 owner_terminal_committed 约束,并调用了无 generation fence 的 persist_usage、transcript materialization 和 run_after_core。当 terminal CAS 返回 Superseded、authority 不确定或 generation 过期时,旧 executor 仍可能覆盖 usage、写入 CSL/hook/observer/promotion/projection,污染企业审计、计费和 ContextPipeline 数据。
请让所有派生写入重新受 terminal owner fence 保护;删除额外的 unfenced usage 写入,只保留 atomic settlement 或 persist_usage_if_current_owner。需要补 terminal CAS=Superseded 的测试,断言这些派生 sink 不会被调用。
- [P1] best-effort projection 被放入 terminal SSE 关键路径
同一段代码在发布 terminal SSE 前 tokio::join! 等待 usage、transcript、hook DB、Memoria observer、SessionEnd hooks、promotion 和 projection。任一 sink 变慢都会阻塞已经 durable committed 的回答,导致客户端超时并触发重复请求;这也与本 PR 的降低 turn latency 目标相悖。
canonical commit、provider settlement、terminal CAS 才是响应正确性的关键路径。请恢复“先完成 terminal SSE,再执行派生 projection”的边界;如果必须提前执行,也必须有明确超时、降级和 owner fence。
- [P2] 删除
reasoning_done/thinking_done的 durable replay 会破坏断线恢复
crates/runtime/src/server/run/lifecycle/run_state.rs 的 terminal persistence 和 live persistence 过滤掉了 reasoning/thinking completion marker。客户端已经收到 reasoning delta 后断线重连时,没有 completion marker 可能无法关闭 thinking UI,直到整个 run 结束。
请保留轻量 completion marker,或先定义并实现明确的 reconnect state snapshot,再删除 marker,并补充断线恢复测试。
- [P1/process] PR 混入了尚未批准且已过时的 #663
PR #670 的 commits 包含 #663 的旧版 edge registry commit(9728d51),但 #663 仍为 Open / CHANGES_REQUESTED,当前 head 已经不同;当前 main 也不包含该 commit。PR 描述中“#663 changes are already part of the base”不成立。请基于最新 main 重新整理纯 latency 分支,避免把未批准的 edge claim/heartbeat/unregister 实现带入本 PR。
正向评价:atomic writer+turn admission、successful inference settlement、PipelineSession-scoped prompt cache、request-scoped discovery snapshot,以及 hash-domain separation 的方向是正确的,也符合 Astra 的企业 durable-agent 定位。但性能优化必须服从 authority fencing、Trace/审计完整性、Runner/Edge side-effect recovery 和断线恢复语义。
9c48ca5 to
6abe5e9
Compare
|
已按 review 完成自检和修复,提交为
本地定向验证通过:两项新增/恢复的 runtime tests、 |
|
The current head
The PR description has also been updated to reflect these ownership, SSE ordering, reconnect, and branch-scope corrections. Please re-review the current head rather than the superseded reviewed commit. |
XuPeng-SH
left a comment
There was a problem hiding this comment.
当前 head 已修复上轮四个问题,但仍有一个需要阻断合并的持久化兼容性问题:
[P1] 复用历史 staged manifest 时没有把它重新激活
persist_database_immutables_in_tx 现在只在新插入时把 reachable 写成 1;当 INSERT IGNORE 命中已存在的相同 manifest 时,代码仅校验 manifest_json,不会把已有行从 reachable = 0 更新为 1。见:
Astra/crates/services/src/session_context_coordinator.rs
Lines 2597 to 2660 in 6abe5e9
这是升级兼容场景,不是理论分支:当前 main 的旧流程会先在独立事务里写入默认 reachable = 0 的 manifest,再在 canonical commit 事务里执行 UPDATE ... SET reachable = 1。进程中断、cursor conflict 或 commit 失败都可能留下内容完整但不可达的 staged manifest。升级到本 PR 后重试相同确定性 delta 会命中这行;随后 session head 被提交为该 manifest root,但 materialize 仍按 reachable = 1 过滤,canonical head 因而指向不可物化的历史。
请在确认 existing manifest 及其 references 完全匹配后,于同一事务显式激活该行(保留 generation/totals 等 fence,并校验恰好一行),并增加回归测试:预置相同 root、reachable = 0 的旧版 staged manifest,重试 commit 后应变为 reachable 且可 materialize。
6abe5e9 to
7ca196d
Compare
|
已修复这个 P1,并将分支 rebase 到最新 |
XuPeng-SH
left a comment
There was a problem hiding this comment.
重新审查了最新 head 7ca196d3。上轮指出的 legacy staged manifest 问题已经正确修复:existing row 与 references 先被完整校验,reachable = 0 再在同一事务内带 fence 激活,并有真实 MatrixOne 的 materialize 回归测试。
当前仍有一个合并阻断项:
[P1] rebase 后 runtime 测试无法编译
最新 main/#690 增加的测试仍调用已被本 PR 重命名移除的 CanonicalRewriteProof::new:
Astra/crates/runtime/src/server/run/lifecycle/tests.rs
Lines 833 to 837 in 7ca196d
本 PR 只保留 CanonicalRewriteProof::from_materialized_admission,因此 clippy、astra-runtime、core crates 和 online integration 都在同一处报 E0599;这不是 CI/flaky 或网络问题,而是确定性的 source integration failure。
请把该测试迁移到 from_materialized_admission,并继续保持两个 hash domain 分离:第二个参数应表达 synthetic/admitted manifest root,不要重新把 canonical_conversation_root(&prior) 当成 manifest root。修复后至少确保 runtime test compile、clippy 和相关测试通过。
7ca196d to
a906bc4
Compare
|
已修复最新 P1,并同时处理了冲突和同源编译问题。分支已 rebase 到 |
XuPeng-SH
left a comment
There was a problem hiding this comment.
Two blockers remain against latest main.
First, insert_trace_events returns the aggregate INSERT IGNORE affected-row count together with events.last() as the last inserted event. A mixed idempotent batch can insert an earlier item while ignoring the final duplicate; the caller then increments event_count but advances last_event_id to an event that was not inserted by this delta, potentially moving the session trace tail backward. Current main updates the tail only for each row that actually inserted. Please preserve the exact inserted tail identity and add mixed existing/new regression cases in both orders.
Second, #698 is now in main, and this PR has a real conflict in canonical_commit.rs. The conflict is semantic: current main uses ProviderCanonical V2, binds replacement authorization to the exact durable predecessor, and makes it one-shot, while this head still carries the older V1 authorization shape while separating manifest and conversation roots. Please rebase and compose both invariants; choosing either conflict side wholesale would regress one of them. Exercise recovery, predecessor mismatch, repeat replacement, and distinct manifest-root/conversation-root cases after integration.
a906bc4 to
7b43498
Compare
|
已基于最新
本地验证:runtime 全量 lib test target 编译通过;trace mixed replay、canonical recovery/one-shot/distinct roots、provider WAL exact predecessor/tamper rejection 均通过; |
XuPeng-SH
left a comment
There was a problem hiding this comment.
Re-reviewed the current head against main, including the full integrated diff. Both prior blockers are resolved: mixed trace replay derives event_count and last_event_id from the actual new-ID set under the session write fence, and the #698 integration preserves exact durable-predecessor binding, one-shot replacement authorization, linear recovery, and separate manifest/conversation hash domains. I also rechecked admission cleanup, successful provider/logical settlement, cancellation recovery, terminal-owner fencing, mailbox wake/poll behavior, and quota snapshot changes. I found no remaining correctness blocker; required CI is green and the merge tree is clean.
Summary
Ports the database-bound turn-latency work from #656 onto current
mainwithout restoring implementation thatmainhas superseded.High MatrixOne latency magnifies serialized reads and writes around a warm agent turn. This change preserves durable, authority, reconnect, and recovery boundaries while reducing avoidable round trips and overlapping causally independent work:
event_countandlast_event_idunder mixed trace replays by resolving existing IDs once under the session write fence and batch-inserting only new IDs;reasoning_done/thinking_donemarkers durable for reconnect while raw reasoning content and deltas remain live-only;PipelineSession;reachable = 0staged manifests inside the canonical commit transaction, preserving generation and aggregate fences without adding a read to the new-manifest hot path.The branch is rebuilt directly on current
main. It contains no #663 Edge registry commit or implementation.Main-specific integration is deliberate:
PipelineSession.mainowns atomic composite checkpoint persistence; this PR keeps that write-through contract and does not restore heavy-checkpoint deferral state.mainperforms authoritative logical-attempt recovery before prompt capture. Prompt capture remains after durable admission so recovery cannot persist a prompt under the preceding attempt identity.No heuristic fast path, Tool/Skill suppression, authorization relaxation, schema migration, public configuration field, compatibility fallback, or parallel state owner is introduced.
Related issue
Follow-up/main port of #656. The original latency investigation and paired MOI integration are tracked in matrixorigin/matrixflow#16389.
Change type
User and compatibility impact
No intended API or user-visible behavior change. Warm Server turns perform fewer serialized database operations. Terminal SSE closes immediately after the durable correctness boundary, so slow derived projections do not extend the visible tail. Reconnect retains reasoning/thinking completion markers. Trace replay updates session counts and tails only for rows actually inserted. No schema or migration is required.
Architecture and complexity delta
SessionContextCoordinatorowns combined admission and writer/turn reservation; inference execution owns atomic successful settlement; runtime lifecycle owns request-scoped capability discovery and owner-fenced post-terminal projection;PipelineSessionowns compiled static prompt sections; the trace writer owns batched idempotent insertion and exact session deltas.Net diff against current
main: 26 files, +2782/-876; zero database tables, migrations, public statuses, or configuration fields.Verification
cargo fmt --allandgit diff --check— passed after rebasing onto perf(runtime): make canonical transition recovery linear #698.cargo test -p astra-runtime --lib --no-run— passed; all runtime tests, including the MatrixOne-gated trace regression, compile.cargo test -p astra-runtime trace_batch_identifies_the_last_new_event_across_mixed_replays --lib -- --nocapture— passed; existing/new and new/existing orders plus repeated new IDs retain the actual inserted tail.cargo test -p astra-runtime turn::canonical_commit::tests --lib -- --nocapture— 2 passed; covers exact predecessor binding, one-shot authorization, recovery, and distinct manifest/conversation roots.cargo test -p astra-runtime provider_wal_planner_binds_rewrite_authority_to_the_exact_durable_snapshot --lib -- --nocapture— passed; V2 durable predecessor binding and tampered authorization rejection are preserved after integration.cargo clippy -p astra-runtime --all-targets -- -D warnings— passed after the perf(runtime): make canonical transition recovery linear #698 rebase and review fixes.trace_batch_tail_tracks_the_last_new_event_in_both_replay_orders; it compiles in the runtime test target but was not executed in this review iteration because no live MatrixOne test environment was configured.cargo check -p astra-services --tests,cargo clippy -p astra-services --tests -- -D warnings, andcargo test -p astra-services session_context --lib— passed for staged-manifest recovery.cargo test -p astra-runtime superseded_terminal_skips_all_owner_derived_projections -- --nocapture— passed; a superseded terminal owner invokes no derived projection sink.cargo test -p astra-runtime terminal_events_for_persistence_keeps_only_terminal_lifecycle_events -- --nocapture— passed; completion markers persist while raw reasoning remains excluded.cargo test -p astra-runtime turn::llm::durable::tests --lib -- --nocapture— 48 passed.cargo test -p astra-runtime typed_objective_relations_survive_real_tiered_compaction --lib -- --nocapture— passed withfrom_materialized_admission.cargo test -p astra-services resource_governor --lib— 17 passed.make test-contract— 10 admin, 4 HTTP, and 2 settings contract tests passed.completion_http_boundary_persists_success_failure_and_caller_cancellationpassed twice on this port: 2.29s including first schema readiness and 0.42s warm.matrixone:latestpassed 20/20 after removing the unsafeINSERT IGNOREaffected-row early return and restoring authoritative settlement-debt identity recovery.make test-offlinepreviously progressed through Server runtime and Web profile tests, then stopped in an unchangedastra-edgetest because this macOS host rejected its temporary workspace-lock namespace. This PR changes neithercrates/astra-edgenorcrates/astra-tools.Public entrypoint exercised on the original #656 tree: local MOI
/chat/streamwith Astra Server and EPH Sandbox, including warm follow-up turns under injected SQL latency. This exactmainport was not redeployed.Unhappy paths covered include authority/cursor conflict, partial admission cleanup, cancellation and lease loss, provider delivery uncertainty, terminal CAS supersession, settlement failure/recovery, missing discovery snapshots, compaction hash mismatch, ProviderCanonical predecessor mismatch/repeated replacement, mixed trace replay ordering, and quota boundaries.
Final checklist