Skip to content

ateapi: backfill unset worker state during pod sync - #599

Open
Mesut Oezdil (mesutoezdil) wants to merge 3 commits into
agent-substrate:mainfrom
mesutoezdil:fix/worker-state-backfill
Open

ateapi: backfill unset worker state during pod sync#599
Mesut Oezdil (mesutoezdil) wants to merge 3 commits into
agent-substrate:mainfrom
mesutoezdil:fix/worker-state-backfill

Conversation

@mesutoezdil

@mesutoezdil Mesut Oezdil (mesutoezdil) commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #517.

#517 added a scheduler filter that skips any worker whose state is not STATE_ACTIVE:

if worker.GetState() != ateapipb.Worker_STATE_ACTIVE {
return false
}

But the syncer writes State only when it creates a worker record. The update path in syncWorkerToStore diffs Ip, SandboxClass and Labels and never touches State, and no other code path writes State onto an existing record.

The store is Redis backed, so worker records outlive an ate-api-server rollout, and worker pods are not recreated by that rollout either. Every worker record written before the State field existed therefore stays at STATE_UNSPECIFIED and is skipped by the scheduler for the whole life of its pod. On an existing cluster upgrading past #517, actor placement fails with ErrNoCapacity until each worker pod is deleted and recreated. The startup sync does not help, because the field diff computes changed == false and never writes.

The scheduler now skips any worker whose state is not STATE_ACTIVE, but the
syncer only sets State when it creates a worker record. The update path diffs
Ip, SandboxClass and Labels and never touches State, and the Redis store
outlives ate-api-server while worker pods are not recreated on upgrade. Every
worker record written before the State field existed therefore stays at
STATE_UNSPECIFIED and is permanently unschedulable, so actor placement fails
with ErrNoCapacity until each worker pod is deleted and recreated.

Backfill the unset state to STATE_ACTIVE when syncing a running pod, which
converges legacy records on the first startup sync. Only the unset state is
backfilled, so a DRAINING worker whose pod name is reused is not resurrected.
ValidateWorker already documents STATE_UNSPECIFIED as tolerated for backward
compatibility, and workflow_resume rejects only DRAINING, so the scheduler's
strict check stays as is.
changed = true
}
if w.State == ateapipb.Worker_STATE_UNSPECIFIED {
// A worker record written before the State field existed. The store

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backwards incompatible changes at this stage of the project is ok. Also, I don't think it's safe to always set UNSPECIFIED to _ACTIVE, we can have a bug somewhere that unset the state field by mistake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants