Skip to content

Cell Loss

A cell that dies takes its running builds with it. Varroa detects the loss, marks the lost builds, and re-fires a build that was granted but never started.

Cell loss detection needs the build record store. An install with the store disabled marks nothing. A tenant that runs the pipeline mesh resumes a running Pipeline build instead, after that page’s own windows.

A stream loss alone is never proof: a network partition leaves a live Jenkins process running builds. A dead stream only makes the operator reconcile sooner.

A pod read is proof. The operator writes the pod’s unique identifier into Controller.status.cell.instance. A pod that is absent, Failed, or Succeeded counts as no pod; a Running or Pending pod does not. A failed read clears nothing, so an API outage never reports a live cell as gone. The placement announcement names each confirmed instance and the time its read proved it.

A confirmed loss reaches a mark in about 70 to 130 seconds. Without a confirmation the recorder falls back to two fixed windows: five minutes for a run whose owning instance changed, and fifteen minutes for a silent run on the current instance.

The operator keeps the replaced instance of each cell in status.cell.previousInstance, and reports it in every announcement. A pod that rolls while the operator restarts, or while the recorder is down, is still confirmed. The 70 to 130 seconds start at the next accepted announcement.

The recorder also compares each announcement with the members it stored. A replaced or removed member pod becomes an unconfirmed dead instance with the five-minute window. This covers two rolls during one recorder outage, and a cell deleted while the operator restarts. The operator reads a left cell until its old pod is gone. A pod that a later announcement names again leaves the list.

The recorder refuses a late announcement from an old operator replica: a lower generation, a pod it knows replaced, or an object that a new one of the same name replaced.

The recorder measures each window on its own clock, so a drifting cell clock moves none. A heartbeat from an instance that no longer owns the run moves no window.

recordStore:
cellLoss:
confirmedGoneGrace: 30s

The grace is how long a confirmation waits before the recorder counts the instance gone. An empty, unparsable, or non-positive value falls back to 30s. The operator can clear its stored cell instance on the tick a replacement pod appears. A zero grace would then interrupt a run the new pod is about to adopt.

A marked build reads INTERRUPTED on the build page and writes one build.interrupted row in the activity feed. The reason names the signal that decided. A completion webhook also sends one synthetic delivery.

ReasonMeaning
cell-lostthe operator read the cell pod and found none
cell-rolledthe cell’s pod changed and the old instance stopped reporting
tenant-movedthe tenant moved and the old instance stopped reporting
no-heartbeatthe run was silent for fifteen minutes on a cell reported not alive
resume-timeoutthe mesh claimed the run and the run did not come back
start-lostno start event arrived 75 minutes after the start mark
heartbeat-lostthe running build was silent for 60 minutes

A cell-lost mark sends no cancel command: the pod is gone. A fleet lock the lost run held is released on the same schedule. A pod read that proved its owner gone ends the five-minute wait.

A start-lost mark sends no cancel and no retry: the build can still start and replace it. A heartbeat-lost mark sends neither, and the build’s own completion replaces it. A Jenkins restart in the same pod sends it at boot. The mark also ends a run on a dead cell when a stopped operator reports no liveness.

The lost instance’s agent pods keep running. A resume adopts a pod that ran a build step, so a Running pod stays for about 41 minutes, or about 46 when no running cell holds the slot. A pod that is not Running goes within about four minutes. See Agent pod lifetime.

A build can be granted and never start, because its cell dies first. Such a build writes no run record, so no sweep can see it.

The recorder re-fires it on the tenant’s current cell, with the same run identifier and intent key, so the rebuilt run keeps its identity and its build number. Five rules gate it.

RuleBehavior when it fails
The owning cell instance is confirmed goneno re-fire; a stream loss alone is never enough
The build carries no parametersno re-fire; a person runs the build again
The tenant holds a live cell and cell instancethe re-fire retries every 60 seconds
The recorder has not re-fired this buildno second re-fire, ever
The build holds no start markno re-fire; the run ends cell-rolled or start-lost

The second rule is permanent: Varroa stores no parameters for a build that never started, so a re-fire would run the job with each declared default.

A backstop fire can reach a cell pod that still boots. The mite then waits up to five minutes for its Jenkins before it sends the trigger. A trigger that still reaches no Jenkins fails with TRIGGER_UNREACHABLE, and the backstop fires the occurrence again on a later round.

A re-fire waits until every earlier fire of the occurrence has failed, or until ten minutes have passed since the last fire. It also waits until cronGrace has passed since the last fire. It goes to the job’s home slot. The backstop re-fires one occurrence at most three times. Any other failure code is permanent, so no round fires that occurrence again.

MetricLabelsMeaning
recorder_cell_loss_confirmed_totalpathruns marked from a confirmed loss
recorder_intent_refired_totaloutcome, reasonre-fire outcomes
recorder_cron_refired_totalnonebackstop re-fires of an unreachable trigger
recorder_interrupted_marked_totalpath, statusevery interrupted mark
recorder_retry_skipped_totalreasonautomatic retries not published
recorder_run_resume_totaloutcome, reasonmesh resume outcomes
recorder_run_resume_timeout_totalnoneruns marked on a resume window