This repository was archived by the owner on Nov 8, 2026. It is now read-only.
Repository navigation
fix(memory): measure and trim the session log without reading it all - #3504
Open
polylane[bot] wants to merge 1 commit into
Open
polylane[bot] wants to merge 1 commit into
polylane[bot] wants to merge 1 commit into
Conversation
Co-authored-by: polylane[bot] <277585245+polylane[bot]@users.noreply.github.com>
Contributor
Author
|
This pull request is waiting on a decision: merge it if the change is still wanted, or close it if the fix is no longer needed. Either one settles it. It was opened on 2026-10-28 and has had no new activity for a week. If nothing happens on it within a week, Polylane closes it and keeps the branch, so reopening it brings the change back exactly as it stands. @justinhelmer and @boristane, the change touches what you own, so the review is with you. |
This branch has not been deployed
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Session logs that grow past the Durable Object memory limit were reset instead of trimmed. The byte policy measured a log by loading every stored turn into memory on each write, and its 200 MiB budget is larger than the 128 MB limit, so a large review transcript could never be measured or trimmed. Writes now measure and trim a log without loading all of it.
flowchart TD A["run writes a transcript turn"] --> B["SessionLogDO /runs/session/write"] B --> C["enforceBytePolicy()"] C --> D["totalBytes(): SELECT every row's json (observed)"] D --> E["isolate holds the whole log's JSON"] E --> F{"log size vs 128 MB isolate limit, budget 200 MiB"} F -->|over| G["isolate reset mid-write, in-flight turn lost"] C -.-> H["fix: SUM(length(CAST(json AS BLOB))) in SQLite"] C -.-> I["fix: page candidate, orphan and fence scans, 256 rows"]Detection evidence
Affected:
acc_017c57bfc0010p0u2hmnjl5uWhy this fix
The per-object metric showed one session log at 144.17 MiB against the 128 MB isolate limit, with a second at 123.31 MiB, and objects keep climbing toward it. Every turn write measured the log by selecting all of its stored JSON into the isolate, and the trim loop re-read it for each candidate, so a log larger than the isolate reset the object instead of shrinking. Summing bytes inside SQLite and reading rows in bounded pages removes that read. The 200 MiB budget is unchanged and intentional; a search over a very large transcript still reads the whole log and is tracked separately.
Fix walkthrough
Watch the fix explained (1:21). Recorded for commit
b18df597f57d74678c6862265d457c98b5059a56.Out of scope
SessionLogDO.search()still reads the whole log when it holds internal transcripts; paging it is tracked on the issue timeline.Production impact: Session log writes trim the same way and read less memory
I checked the switchboard-memory worker and its SessionLogDO namespace on coreplane-infra, which served 72,381 requests and 5 errors in the last 48 hours, with top objects at 123.31, 60.34 and 50.64 MiB. The changed methods are private to SessionLogDO; the byte-policy, trimming and attachment tests pass unchanged, and the SQL aggregate returns the same UTF-8 byte total the JS sum returned.
Checked and not affected:
switchboard-memory,bcb98cc3b42b4c79b9896fd28579efdb.Observability
durableObjectsPeriodicGroups.max.memoryUsageByteson namespaceswitchboard-memory_SessionLogDOshows whether a log still approaches the 128 MB limit.POST /runs/session/writeresponse carriesbytesfromenforceBytePolicy(), so the measured total after each write is visible per request.Polylane assessed this pull request at
b18df59.Causal chain
SELECT idx,part,json FROM turnsand summed utf8ByteLength in JS; enforceBytePolicy calls it on every write and re-measures each trim pass.SELECT idx, json FROM turns(now SessionLogDO.pinnedRowReferences).1 file changed (+113/-52)
deploy/cloudflare-memory/worker.ts: modified, +113/-52Generated by Polylane. You can ask follow-ups by mentioning @polylane in a comment.