Skip to content

Instance lifecycle

Every ChallengeInstance reports a status.phase driven by two controllers: the instance controller (pod health) and the lifecycle controller (TTL).

stateDiagram-v2
    [*] --> Pending
    Pending --> Creating : template Ready
    Creating --> Running : pod passes readiness
    Running --> Unhealthy : readiness fails ≥ threshold
    Unhealthy --> Running : readiness recovers
    Running --> Expiring : TTL − 60s
    Expiring --> Running : extended in time
    Expiring --> Expired : TTL reached
    Expired --> [*] : instance deleted,\nworkload garbage-collected
    Pending --> Failed
    Creating --> Failed
    Running --> Failed

Phases

Phase Meaning
Pending Waiting for the referenced template to become Ready.
Creating Workload created; waiting for the pod to be scheduled and pass its readiness check.
Running Pod is up and ready. status.endpoint points at the service.
Unhealthy Pod is running but has failed readiness at least unhealthyThreshold times (default 3). Recovers to Running on its own if readiness returns.
Expiring Inside the 60-second grace window before TTL expiry. The backend gets an instance.expiring event — time to warn the player.
Expired TTL reached. The instance is deleted; its Deployment, Service, and NetworkPolicy are garbage-collected.
Failed Terminal error: template missing, invalid TTL, or the pod itself failed.

Expired and Failed are terminal — the controllers stop reconciling an instance in those phases.

TTL and extension

The effective TTL is the template's spec.ttl, unless the instance sets spec.ttlOverride. status.startedAt is stamped once when the workload first comes up, and status.expiresAt is always startedAt + effective TTL.

Because expiresAt is recomputed on every reconcile, extending a live instance is just a spec update — which is exactly what the API's extend endpoint does:

curl -X PATCH localhost:8080/api/v1/instances/demo-web-team-alpha/extend \
  -H "Authorization: Bearer $KIMO_API_KEY" \
  -d '{"ttl": "2h"}'

The TTL is total-from-start, not from-now: extending to 2h means the instance lives two hours from startedAt. An instance already in Expiring recovers to Running if extended in time; an Expired instance is gone and cannot be resurrected — launch a new one.

Backend events

Each transition emits one event to the scoring backend:

Phase entered Event
Creating instance.creating
Running instance.running
Unhealthy instance.unhealthy
Expiring instance.expiring
Expired instance.expired
Failed instance.failed
deleted via API instance.deleted