Task Execution Lifecycle
Status: Implemented
Purpose
Task-mode Runs execute one bounded command or script on an assigned warm Runtime Pod. This document defines the boundary between local asynchronous work in runtimed and Kubernetes control-plane state.
The invariant is simple: only reconciliation updates Run.status. A local
worker must never read a Run directly to bypass an informer cache, and must
never update Run status itself.
Lifecycle
After scheduler assignment, the owning runtimed handles a Task Run as follows:
- A cached
ScheduledRun is claimed and updated toRunning. - Source preparation happens before execution starts. A preparation error is applied by that same reconciliation as the normal Run failure path.
- A later reconciliation of the cached
RunningRun calls Runtime ServerStatus. - When
StatusreturnsNOT_FOUNDand no execution has been observed:- an asynchronous worker starts artifact input staging and Runtime Server
Executeif another start is not already in flight; - otherwise runtimed requeues the Run and waits.
- an asynchronous worker starts artifact input staging and Runtime Server
- When Runtime Server reports
PENDINGorRUNNING, runtimed records that the execution exists and adds it to the Run Lifecycle Event Generator (RLEG). SUCCEEDEDandFAILEDare applied by reconciliation using the ordinary output, artifact, retry, and terminal-state rules.
Once an execution has been observed, a later Runtime Server NOT_FOUND is an
ExecutionLost failure. This distinguishes an execution that has not yet been
created from one that disappeared after being accepted.
Asynchronous Start Boundary
Artifact input staging and Execute may block on storage or the local Runtime
Server, so they run asynchronously. The worker only performs local work:
- On success, it records completion locally and enqueues the Run.
- On failure, it records the failure locally, emits an Event and a log entry, and enqueues the Run.
- If the Run is no longer locally active when
Executesucceeds, runtimed forgets the created Runtime execution instead of reviving the Run.
The next reconciliation consumes a recorded start failure and applies it using
the normal retry policy. This includes failures while staging artifact inputs:
they are reported as Runtime execution-start failures, but no asynchronous
worker writes Run.status.
Retry
When a Task attempt fails but remains retryable, runtimed first persists the
retry status and forgets that terminal Runtime execution. When retry backoff
expires, runtimed clears the previous attempt’s local execution observation,
changes the Running condition back to true, and requeues. It
does not invoke Execute from that status-update call. The subsequent cached
Running reconciliation observes Runtime Server NOT_FOUND and starts the
next execution attempt. Forgetting the terminal result is necessary because a
Runtime Server keys executions by immutable Run UID; otherwise the next
reconciliation would mistake the previous attempt’s FAILED result for the
new attempt.
This structure avoids racing an asynchronous local operation against the controller cache immediately after a status update, while retaining bounded reconciliation and the existing at-least-once execution semantics.