test(runtime): add persistence observer streaming benchmarks - #4077
Open
salignatmoandal wants to merge 1 commit into
Open
test(runtime): add persistence observer streaming benchmarks#4077salignatmoandal wants to merge 1 commit into
salignatmoandal wants to merge 1 commit into
Conversation
salignatmoandal
force-pushed
the
bench/persistence-observer-streaming
branch
from
August 30, 2026 21:00
36cfbd2 to
084471c
Compare
Collaborator
|
👋 Some commits in this PR are not signed and verified by GitHub. Please sign your commits with a GPG or SSH key registered in your GitHub account, then force-push. Commits that are not verified: See GitHub's guide on signing commits for setup instructions. I've added |
salignatmoandal
force-pushed
the
bench/persistence-observer-streaming
branch
from
August 30, 2026 21:02
084471c to
5cbf63a
Compare
Document the per-chunk AddMessage/UpdateMessage contract and establish in-memory vs SQLite baselines for streaming assistant persistence.
salignatmoandal
force-pushed
the
bench/persistence-observer-streaming
branch
from
August 30, 2026 21:13
5cbf63a to
e40f6b6
Compare
Author
|
Hi @aheritier, thanks for the heads-up. I've signed the commit with my SSH signing key and force-pushed (e40f6b6). GitHub now shows it as verified on my side. Happy to adjust anything else if needed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds characterization tests and benchmarks for
PersistenceObserverstreaming persistence — the path that mirrors assistant token deltas (AgentChoice/AgentChoiceReasoning) into a single growing message row in the session store.This establishes a baseline before any future optimization (e.g. debounced flushes) and documents the per-chunk store write contract that the observer currently implements.
Context
During a streaming assistant turn, the runtime emits one
AgentChoiceEventper delta.PersistenceObserver.persistStreamingContentkeeps a single in-flight row and:AddMessage) on the first chunkUpdateMessage) on every subsequent chunkMessageAddedEventto finalise the row with the canonical payloadThis behaviour is easy to regress when refactoring persistence or the store layer, but was not previously covered by a focused unit test or benchmark.
Changes
New file:
pkg/runtime/persistence_observer_bench_test.goTests
TestPersistenceObserver_UpdateCountPerChunkAddMessage+(N-1)UpdateMessagecalls for N streaming chunks, plus one finalUpdateMessageonMessageAddedTestPersistenceObserver_StreamingContentAccumulates"hel"+"lo"→"hello")Both tests use a
countingStorewrapper aroundInMemorySessionStoreto assert store call counts without mocking the observer.Benchmarks
Each iteration simulates a long assistant turn: 500
AgentChoicedeltas + 1MessageAddedfinalisation (streamingBenchChunks = 500).BenchmarkPersistenceObserver_StreamingChunksInMemorySessionStoreBenchmarkPersistenceObserver_StreamingChunks_SQLite:memory:json.Marshal+UPDATE session_itemsper chunkSample results (darwin/arm64, Apple M3 Pro)
Per chunk (500 chunks/iter): ~4 µs in-memory, ~6 µs SQLite, ~5 vs ~17 allocs.
SQLite is ~1.5× slower and ~3× more alloc-heavy — expected given JSON marshal + SQL per update.
Known benchmark caveats
b.Niterations, soUpdateMessageeventually scans an ever-growing message list (O(messages) per update). Later iterations are slower than the first. SQLite stays flat because updates are keyed bymessage_id.NewSQLiteSessionStoreFromDB, which logs migration info beforeb.ResetTimer()— noisy stdout but not included inns/op.These caveats are acceptable for a baseline but worth keeping in mind when comparing future numbers.
Why now?
Streaming persistence is on the hot path for every assistant response when a session store is configured. Having explicit tests + benchmarks makes it safer to:
persistStreamingContent(avoidstrings.Builder.String()copies on every delta)Test plan
go test ./pkg/runtime -run TestPersistenceObserver_UpdateCountPerChunk -vgo test ./pkg/runtime -run TestPersistenceObserver_StreamingContentAccumulates -vgo test ./pkg/runtime -run=^$ -bench=BenchmarkPersistenceObserver -benchmem -count=1task test(full suite)task lint