Session retention
Session retention controls how long Sessions keep node outputs and when whole sessions are removed. Policies are declared on the Session Template configuration JSON. The platform enforces them in the background and records effective settings in each session’s metadata.retentionStatus (visible through integrator APIs where exposed).
A session moves through up to four stages as it sits idle. Each stage is a threshold in the template; the platform runs whichever are declared.
| Stage | Trigger | Survives | Lost |
|---|---|---|---|
| Live | session active | everything | nothing |
| Reprocessable | ArchiveByAge threshold | inputs, the current output of every node, skipArchive nodes | superseded intermediates |
| View only | inputs.threshold | dashboards, current outputs, skipArchive nodes | raw inputs (the ingest) |
| Gone | DeleteByAge threshold | nothing | the session |
The mode (ArchiveByAge or DeleteByAge) and the inputs stage are independent. A template can declare either, both, or neither.
Three modes
| Mode | When it runs | Input nodes | Other nodes |
|---|---|---|---|
| KeepAll | Never (default) | All outputs kept | All outputs kept |
| ArchiveByAge | After idle period | All outputs kept | Only the latest output kept per node (unless opted out) |
| DeleteByAge | After idle period | Session deleted | Session deleted (including ingest data) |
Idle period is measured from last activity: the newest NodeOutput.CreatedAt in the session. If the session has no outputs yet, Session.CreatedAt is used.
Threshold uses Kubernetes-style durations, for example 1s, 30m, 1d, or 1d 12h.
Template configuration
Authoritative policy lives in the session template root configuration:
{
"retentionPolicy": {
"mode": "ArchiveByAge",
"threshold": "3d"
}
}When a session is created, the platform stamps retentionStatus into session metadata:
{
"retentionStatus": {
"mode": "ArchiveByAge",
"threshold": "3d",
"lastActivityAtUtc": "2026-05-18T12:00:00.000Z",
"lastEnforcedAtUtc": null
}
}lastActivityAtUtc: Updated when enforcement runs and on create.lastEnforcedAtUtc: Set after a successful archive or delete sweep for that session.inputsThreshold: Copied fromretentionPolicy.inputs.thresholdwhen declared.inputsRemovedAtUtc: Set once the inputs stage has run (see Input retention).
Omit retentionPolicy or set mode to KeepAll for legacy behaviour (no automatic cleanup).
Input retention (view-only sessions)
The raw ingest (every output of the session’s Input nodes, such as the capture protobuf uploaded to input-node) is usually the largest thing a session stores, and it is only needed to reprocess the session. Declare retentionPolicy.inputs.threshold to remove it after an idle period while keeping every other node’s outputs, so dashboards keep working:
{
"retentionPolicy": {
"mode": "ArchiveByAge",
"threshold": "7d",
"inputs": { "threshold": "90d" }
}
}inputs combines with any mode. With KeepAll (or no mode) the session keeps every output forever except the inputs: a view-only session for the life of the environment. With DeleteByAge the inputs go first and the session later.
What the inputs stage does, once per session:
- Waits until the session is settled: no task is available, claimed or retrying; no node is pending or processing; every node that records an incremental watermark against an input parent has consumed the newest input row. An unsettled session is skipped and retried on a later sweep.
- Removes every Input node
NodeOutputrow and deletes each storage object no remaining output references (heatx keys shared with a cloned session survive). - Stamps
retentionStatus.inputsRemovedAtUtcin session metadata. The stage never runs twice for a session.
After the stamp, the session is view-only:
- Reprocess is refused for Input nodes and for their direct children (the nodes that read the ingest), with a message naming the removal time. Nodes further down the DAG still have their parents’ current outputs and can be reprocessed, so dashboard scripts can still be corrected.
- Clone by output reference of the input node has nothing to clone.
- Sessions that back a Static instance are skipped, as for
DeleteByAge.
If a session may need reprocessing on a future template revision, export it before the inputs threshold elapses. Viewing a session does not count as activity, so a session that is only ever viewed still progresses through the stages.
Per-node archive opt-out
Node instances copy defaultConfiguration from the template. Add retention.skipArchive to keep all outputs for that node during ArchiveByAge (the node is still removed on DeleteByAge):
{
"retention": {
"skipArchive": true
}
}Use this on dashboard rollup nodes (for example cluster-usage-history, dataservice envelope, Next dimension) while allowing high-volume upstream nodes (for example cluster-report) to trim to the latest snapshot only.
Input node templates (NodeType.Input, such as input-node) are never archived; ingest and heatx history stay intact until the inputs stage runs or the whole session is deleted.
What archive deletes
For each eligible non-input node:
- Keep
CurrentOutput(or the newest output if unset). - Remove other
NodeOutputrows. - Delete S3 objects when no remaining output references the same
bucket+object_name(shared heatx keys use reference counting). - Repoint
SessionDimensionandRunnerTask.LastRunnerOutputreferences to the kept output where needed.
Non-heatx and heatx-backed outputs in the managed bucket heat-{sessionId} follow the same rules.
What delete removes
DeleteByAge clears FK blockers (including NodeInstanceLink DAG edges, CurrentOutputId, session dimensions, runner-task output refs, and any StaticInstance rows still pointing at the session), deletes all objects in the session S3 bucket, then removes the session row (cascade removes node instances and outputs). Sessions that back a Static instance are skipped by the automatic sweep; use a privileged force delete only for testing (force delete also removes those static instance rows).
Background enforcement
The platform runs retention on a schedule (default about every 5 minutes). Operators can tune the interval with system.retention.tick_minutes in Platform configuration.
Statics and Resource Monitor
High-frequency static refresh (for example Resource Monitor at one minute) can produce thousands of cluster-report outputs per backing session. Combine:
- Backing-session rotation on the static definition (
backingSessionRotation.period, e.g.24h) to start a new session each period (see Statics). - ArchiveByAge on the template (shipped
heat-system-resource-monitor-nextuses7d), withskipArchiveon rollup and dashboard nodes, to trim outputs inside the current backing session.
Upgrade an existing static definition to a new template revision through your deployment team’s template upgrade workflow when you adopt retention on a running cluster.