Repository navigation
Description
Today Substrate doesn't have any special handling of worker pod deletions. If the worker pod assigned to a RUNNING actor is deleted, the system gets into a corrupted state where the control plane still thinks it's RUNNING. Moreover, we don't do any graceful suspension of the actor.
Additionally, the way we sync worker pods into the control plane Valkey is fragile and can drift.
This issue is to design a more robust handling of pod deletion, where we hook into the deletion process (via a finalizer) and perform a graceful worker pod deletion. This involves suspending the actor. It's unclear to me if it's needed to also resume it on a different worker pod, sort of a live actor migration, but I'll assume that just suspending is enough for now.
The model I have in mind is one where we externalize the registration and de-registration of worker pods to a dedicated controller running centrally inside atecontroller. I'll refer to this controller as the "wp-controller".
Worker Pod Creation
- The user creates or updates a
WorkerPoolcustom resource. - The
WorkerPoolcontroller creates a Kubernetes Deployment. Pods get a finalizer (e.g.,ate.gke.io/worker-cleanup). - The wp-controller observes the newly created Pod object and immediately calls
RegisterWorker(NOT_READY)onate-apiserver.
Registration
- Kubernetes schedules the worker pod, assigns it an IP address, and starts the
ateomcontainer. - Kubelet periodically probes worker pod readiness. Once
ateomcompletes boot and verifies internal runtime health, the probe passes and kubelet marks the Pod condition asReady = True. - The wp-controller observes the
Ready = TruePod update and callsMarkWorkerReady(IP)onate-apiserverto transition the worker toREADY.
Running
- The worker is now in
FREEstate. - When an actor needs to be resumed, the
ateapiserver picks this worker and assigns the actor to it. - The worker handles requests for that actor until the actor is suspended.
Deregistration / Deletion (Controller-Driven)
- Kubernetes initiates a Pod deletion (e.g., scale down, node drain), setting
deletionTimestampon the Pod and sendingSIGTERMto theateomcontainer (we will need to set a generous grace period on the worker pod). ateominterceptsSIGTERMand sheds incoming HTTP traffic by returning503 Retry-After.- The wp-controller observes the
deletionTimestamp != nilupdate on the Pod and drives the graceful suspension:- Calls
CordonWorkeronate-apiserverto prevent new actor assignments. - Checks if the worker has a running actor. If so, calls
SuspendActoronate-apiserver.ate-apiserverthen callsateletover gRPC to initiate a memory checkpoint of the active actor. - Once suspension completes (or if no actor was assigned), calls
UnregisterWorkeronate-apiserverto purge the worker from Valkey. - Removes the finalizer from the Pod, allowing Kubernetes to permanently purge the Pod object from etcd.
- Calls
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
ateapi/syncer: tighten releaseActorOnDeadWorker doc comment
ateapi/syncer: release actor when host pod is deleted
sfunkenhauser commentedon Jul 23, 2026
I've put together a 1-pager on how we can handle graceful termination.
The idea of a wp-controller and worker API needs a bit more investigation.
docs(observability): add actor application telemetry best practices
docs(observability): mark actor telemetry guidance as interim
Handle graceful worker termination (#517)
sfunkenhauser commentedon Aug 4, 2026
Keeping this issue to track the core pod eviction/graceful termination work.
I've filed #728 #729 #730 to track changes to the worker API and WorkerPoolSyncer.
Handle graceful termination in gvisor ateom (#764)
Handle graceful termination in microvm ateom (#893)