fix: prune stale session entries, cap entry count, and rotate sessions.json#12920
Closed
skyfallsin wants to merge 1 commit intoopenclaw:mainfrom
Closed
fix: prune stale session entries, cap entry count, and rotate sessions.json#12920skyfallsin wants to merge 1 commit intoopenclaw:mainfrom
skyfallsin wants to merge 1 commit intoopenclaw:mainfrom
Conversation
306a3d1 to
4f31c6f
Compare
36d7737 to
21b8849
Compare
…s.json
The sessions.json file grows unbounded over time. Every heartbeat tick (default: 30m)
triggers multiple full rewrites, and session keys from groups, threads, and DMs
accumulate indefinitely with large embedded objects (skillsSnapshot,
systemPromptReport). At >50MB the synchronous JSON parse blocks the event loop,
causing Telegram webhook timeouts and effectively taking the bot down.
Three mitigations, all running inside saveSessionStoreUnlocked() on every write:
1. Prune stale entries: remove entries with updatedAt older than 30 days
(configurable via session.maintenance.pruneDays in openclaw.json)
2. Cap entry count: keep only the 500 most recently updated entries
(configurable via session.maintenance.maxEntries). Entries without updatedAt
are evicted first.
3. File rotation: if the existing sessions.json exceeds 10MB before a write,
rename it to sessions.json.bak.{timestamp} and keep only the 3 most recent
backups (configurable via session.maintenance.rotateBytes).
All three thresholds are configurable under session.maintenance in openclaw.json
with Zod validation. No env vars.
Existing tests updated to use Date.now() instead of epoch-relative timestamps
(1, 2, 3) that would be incorrectly pruned as stale.
27 new tests covering pruning, capping, rotation, and integration scenarios.
21b8849 to
c26c0b2
Compare
Contributor
Author
|
greptile feedback addressed |
Member
|
Fix landed on main via e19a235. Thanks @skyfallsin! |
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.
Problem
sessions.jsongrows unbounded over time. Every heartbeat tick (default: 30m) triggers multiple full rewrites, and session keys from groups, threads, and DMs accumulate indefinitely with large embedded objects (skillsSnapshot,systemPromptReport). At >50MB the synchronous JSON parse blocks the event loop, causing Telegram webhook timeouts and effectively taking the bot down.Fix
Three mitigations, all running inside
saveSessionStoreUnlocked()on every write:1. Prune stale entries
Remove entries with
updatedAtolder than 30 days. Entries withoutupdatedAtare preserved (cannot determine staleness).2. Cap entry count
Keep only the 500 most recently updated entries. Entries without
updatedAtare evicted first (lowest priority).3. File rotation
If the existing
sessions.jsonexceeds 10MB before a write, rename it tosessions.json.bak.{timestamp}. Only the 3 most recent backups are kept.Configuration
All three thresholds are configurable via
openclaw.jsonundersession.maintenance:{ "session": { "maintenance": { "pruneDays": 30, "maxEntries": 500, "rotateBytes": 10485760 } } }All fields are optional — built-in defaults apply when unset. No env vars are used; configuration is purely through
openclaw.json.The
SessionMaintenanceConfigtype is added totypes.base.tsand the Zod schema is added tozod-schema.session.ts.The three exported functions also accept an optional override parameter for direct use in tests or programmatic callers:
pruneStaleEntries(store, overrideDays?)capEntryCount(store, overrideMax?)rotateSessionFile(storePath, overrideBytes?)Changes
src/config/sessions/store.tsresolveMaintenanceConfig()reads fromopenclaw.json, wired intosaveSessionStoreUnlocked()src/config/sessions/store.pruning.test.tsloadConfigto control configsrc/config/types.base.tsSessionMaintenanceConfigtype definitionsrc/config/zod-schema.session.tsmaintenancefield added toSessionSchemasrc/config/sessions.test.tsDate.now()instead of epoch-relative timestampsTest results
72 tests pass (7 test files).
Notes
createSubsystemLogger("sessions/store")at info level when entries are pruned, capped, or the file is rotated.Greptile Overview
Greptile Summary
This PR adds automatic
sessions.jsonmaintenance during session store writes: pruning entries older than a configurable age, capping total entries to a configurable maximum, and rotating the on-disk file when it exceeds a size threshold (keeping a small set of.bak.{timestamp}backups). Configuration is wired throughopenclaw.jsonundersession.maintenancewith a newSessionMaintenanceConfigtype and Zod validation. Migrations are updated to be able to bypass maintenance during one-time legacy merges.One issue to fix before merge: the new pruning/capping/rotation test suite references
crypto.randomUUID()without importingcrypto, which will break in environments wherecryptois not a global in tests.Confidence Score: 4/5
cryptoidentifier which can cause CI failures depending on the test runtime globals.(2/5) Greptile learns from your feedback when you react with thumbs up/down!