Repository navigation
feat(core): add storage.sessions config to delete old sessions - #57882
opencode-agent[bot] wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
This works as described. I ran serve from source with isolated config and data dirs and moved two sessions' time_updated back 40 days. With session_retention: "30 days" only in the project's opencode.json, nothing was deleted. With it in the global opencode.json, startup deleted the two old sessions and kept the recent one. The new tests and the normalization test pass, and type checks pass for core (with tests) and server.
Public API: adds an optional session_retention config key (a duration string) to Config.Info, plus the matching OpenAPI schema and generated client type. Nothing is removed or changed and the default is unset, so this is backwards compatible. The key is only read from global, system and managed config; if it is set in a project config it is accepted but ignored.
One thing worth fixing: the sweep rebuilds a full config service every hour just to read one key (see inline comment).
Related: #55293
| const SWEEP_INTERVAL = Duration.hours(1) | ||
|
|
||
| /** Reads `session_retention` from global, system, and managed config. Project config never applies. */ | ||
| export const configured = Effect.fn("SessionRetention.configured")(function* () { |
There was a problem hiding this comment.
configured() builds a new Config.layer on every hourly sweep, even when session_retention is unset. That layer does more than read files: it sets up watchers on the config roots (in my run they started and stopped on /etc and /root at each sweep), resolves well-known config again (an HTTP fetch of remote_config for organisations that use one), and forks reload and refresh fibers that are thrown away right after. Every user would pay this cost hourly just to read one key. Could this read the global, system and managed documents in a lighter way (for example ConfigDiscovery plus parsing just those files), or keep one long-lived global-scoped config instead of rebuilding it each sweep?
0ee0d22 to
eff2fd6
Compare
Issue for this PR
Part of #16101
Type of change
What does this PR do?
Adds a
storageconfig group with one field,storage.sessions. It takes a duration and is unset by default, so sessions are kept forever unless you opt in. The group can hold other local-data cleanup later (e.g.storage.snapshots).{ "storage": { "sessions": "30 days" } }SessionExpiry(packages/core/src/session/expiry.ts, new) runs an hourly global sweep next to the project archive sweep:update. It readsconfig.json,opencode.json, andopencode.jsoncfrom the global config directory, parses JSONC, and usesstorage.sessionsfrom the last file that sets it. Project config is never read, so a project can't delete other projects' sessions. As withupdate, a project-level value is silently ignored, and system/MDM-managed config and{env:...}substitution don't apply.time_updatedis older than the cutoff are removed throughSession.remove, so children, events and projections go the same way as a manual delete. Suspended sessions (owned by restart recovery) and sessions with an active execution or running background job are skipped. Non-finite or zero durations are ignored with a warning.Deleting rows doesn't shrink
opencode.dbby itself; reclaiming pages is separate (#56365).How did you verify your code works?
bun test test/session-expiry.test.ts: deletes an expired top-level session and its child, keeps a recent one and a suspended one, reads the value from a temp global config dir (unset → keep), and decodes JSONC edge casesbun test test/config/normalization.test.tswith a newstorage.sessionscasesession-create,config,workerdtests with the node in the route graphtsc -bfor core (including tests) and server; regenerated protocol/www OpenAPI and client typesScreenshots / recordings
N/A
Checklist
Requested by: @jlongster (James Long via Slack)