Skip to main content
Version: v5.7.0

Maintenance window

maintenance

A maintenance window quiesces one node's subtree: new work targeting it is deferred (or admitted through the window's allow lists) until the window ends. The JSON:API resource type is maintenance_window (verified in serializeMaintenanceWindow), with the window row's id as the resource id and a links.self of /api<node path>/maintenance.

The v2 OpenAPI document declares this resource's schema; the resource-field coverage gate holds this page to it.

Endpoints (node-scoped ones ride the node's …/maintenance RBAC rule path — read for status, update for every write — 404-on-deny):

  • GET <node>/maintenance — the node's own not-ended window, or the inactive shape {"data": null, "meta": {"active": false}}.
  • POST <node>/maintenance — start (201); POST <node>/maintenance/end — end (200).
  • POST <node>/maintenance/schedule (201), /cancel, /extend — the scheduled-window lifecycle.
  • GET /api/maintenance — the estate listing: every active and scheduled window the caller can read; ?ended=true adds ended ones, optionally bounded by ?since=<RFC3339>.
  • GET /api/maintenance/{window_id}/deferred_firings — the window's parked trigger firings, original event order.
  • POST /api/projects/{project_code}/triggers/{id}/firings/{firing_id}/discard — prune one parked firing before release (only a deferred firing discards).

Attributes​

All timestamps are strings in 2006-01-02T15:04:05.000000Z (UTC), or null.

FieldTypeMeaning
activeboolWindow has started and not ended (started_at set, ended_at null).
scheduledboolWindow awaits its auto-start (started_at null, ended_at null).
reasonstringThe operator's required reason, from start/schedule.
untilstring/nullDeclared intent only on a manually started window — the window never auto-closes on it — but it bounds deferral expiry at release. Null when not declared. Extend updates it on a manual window.
scheduled_startstring/nullA scheduled window's declared from — when the engine auto-starts it. Null on manually started windows.
hard_endstring/nullA scheduled window's declared to — a hard end the engine enforces (unlike the advisory until). Null on manual windows. Extend updates it on a scheduled window.
auto_extend_secsint/nullPer-increment extension the engine applies while the window's declared work is unfinished. Null unless scheduled with it.
max_extension_secsint/nullThe fail-open cap on total auto-extension; defaults to 7200 (2h) when auto-extension was asked for without a cap. Null when auto-extension is not set.
auto_endboolThe engine ends the window when its stamped declared work completes.
runsstring arrayThe declared workflow codes the engine creates at auto-start (as the scheduling operator). Always present; [] when none.
allowobjectThe window's declared maintenance work — {"workflows": [], "actions": [], "users": []}, each always present as a string array. Any one list matching a create (workflow code, change action, requesting username) admits it through the quiesced subtree.
started_bystring/nullUsername the start (or auto-start) is attributed to. Null while scheduled, and when the starting principal no longer resolves.
started_atstring/nullWhen the window became active. Null while scheduled.
ended_bystring/nullUsername that ended the window. Null until ended.
ended_atstring/nullWhen the window ended. Null until ended.
deferred_countintThe window's live parked-firing count (trigger firings with status deferred parked by this window) — computed per read via an indexed subselect.

Window state vocabulary​

There is no single state string; the lifecycle is read from the two booleans and ended_at, exactly as derived in scanMaintenanceWindow:

  • scheduled — started_at null and ended_at null (scheduled: true).
  • active — started_at set and ended_at null (active: true).
  • ended — ended_at set (both booleans false). Ended windows appear only in the estate listing with ?ended=true.

A node holds at most one not-ended window (a partial unique index is the race-safe backstop); starting or scheduling over one is a named 422, as is ending when none is active. Cancelling requires the window id and only removes a window that has not started; extending refuses anything that would shorten the window.

What changes it​

Start/End emit api:nodes:maintenance_started / _ended, Schedule emits api:nodes:maintenance_scheduled, Extend api:nodes:maintenance_extended — ordinary triggerable events. Release of deferred firings rides the maintenance_ended event; a discarded firing settles suppressed, keeping its deferred_window_id as history.

  • opschain docs maintenance-windows — the gate, deferral and release narrative.