Skip to Content
This documentation is provided with the HEAT environment and is relevant for this HEAT instance only.
InternalCore APISession scheduling freeze (Core API)

Session scheduling freeze (Core API)

Operator handbrake for a single session. While frozen, the Core API stops all runner task scheduling for that session without deleting or mutating any task rows. Internal only, not exposed on v1/v2 public APIs.

Use it when a session is stuck in a task churn loop (for example a bad session template revision on site) and you need it to stop consuming runner capacity while you decide how to recover.

How it is stored

The flag is a freeze object in session metadata. No schema or session DTO change; the object rides inside the existing metadata blob:

{ "freeze": { "frozenAtUtc": "2026-07-02T00:45:00Z", "reason": "r020 template runaway" } }

Managed by SessionFreezeMetadataHelper (merge, clear, read). Other metadata keys are preserved.

Endpoints

RouteEffect
POST /api/sessions/{id}/freeze?reason=...Sets the freeze flag. reason is optional. 409 when already frozen.
POST /api/sessions/{id}/unfreezeClears the flag. 409 when not frozen.
POST /api/sessions/freeze-by-template/{sessionTemplateId}?reason=...Mass freeze: sets the flag on every session using the template. Already-frozen sessions are skipped, not an error. 404 when the template does not exist.

Freeze and unfreeze append a session timeline event (SessionFrozen = 30, SessionUnfrozen = 31); the mass variant appends SessionFrozen per session it freezes.

The mass endpoint returns a summary body (SessionFreezeByTemplateResult): total sessions on the template, frozen and already-frozen counts, and the session id lists for both. There is no mass unfreeze; unfreeze each session individually after verifying the cause is fixed.

What freeze gates

All checks live in RunnerTaskService and read the metadata flag app-side:

  • Task creation: CreateTaskAsync rejects and ShouldCreateTaskAsync returns false. Node status updates from still-running tasks (heartbeats, fail reports) can no longer mint child tasks or new ReferenceTime task rows.
  • Task claiming: ClaimTaskAsync filters out tasks whose session is frozen. The existing backlog (Available and retryable Failed rows) stays in the database untouched but is invisible to runners.
  • Scheduler visibility: GetPendingTasksAsync (feeds the task-types endpoint used for runner provisioning) and GetTaskPressure exclude frozen sessions, so a frozen backlog does not keep runner deployments provisioned or inflate pressure.

What freeze does not do

  • It does not abort work already executing on a runner. In-flight executions run to completion; their signal, complete, and fail calls are still accepted so runners end cleanly. For an immediate stop, freeze first, then delete the runner pods; abandoned tasks are released on the runner’s next claim and are then unclaimable while frozen.
  • It does not change retry semantics, supersede behavior, or task state for any other session.
  • It does not block ingestion or data reads. Only runner task scheduling is gated.

Recovery flow for a runaway session

  1. POST /api/sessions/{id}/freeze?reason=...
  2. Optionally delete the runner pods currently executing the session’s tasks.
  3. Investigate or migrate the session (for example re-run under a corrected session template revision).
  4. POST /api/sessions/{id}/unfreeze only if the underlying cause is fixed; the untouched backlog becomes claimable again immediately.