VectorFlow
Operations

Deploy State Machine

This document describes the deploy path that starts when a pipeline is edited and ends when agents report runtime status. It is for maintainers and operators who need to reason about deploy approvals, rollback, concurrent deploy attempts, and agent status.

After reading it, you should be able to decide whether a deploy, approval, rollback, agent poll, or heartbeat transition is valid without reading the implementation.

State owners

VectorFlow splits deployment state across five records:

RecordOwnsImportant states
PipelineWhether the pipeline is draft or deployed, plus current editor graph and node selectorDraft, deployed, undeployed
Pipeline versionImmutable deployed snapshot of generated YAML, global config, nodes, and edgesVersion numbers increase monotonically
Deploy requestApproval workflow for environments that require reviewPending, approved, rejected, cancelled, deployed
Agent config responseThe versioned configs a node should run after pollingOmitted, delivered
Node pipeline statusRuntime status reported by heartbeatsPending, starting, running, stopped, crashed

Pipeline edits change the live pipeline graph only. Agents never receive live graph edits directly. Agents receive the latest pipeline version snapshot only after a deploy path creates a new version and marks the pipeline deployed.

Pipeline and version transitions

FromEventToResult
Draft or deployed pipeline with edited graphDeploy previewSame stateGenerated YAML and validation result are returned; no version is created.
Draft or deployed pipelineDirect deploy succeedsDeployed with a new versionA new immutable version is created from the current graph, the pipeline is marked deployed, matching agents are notified to poll.
Draft or deployed pipelineDirect deploy validation failsSame stateNo version is created and the pipeline is not marked deployed.
Draft or deployed pipeline in an approval-required environmentEditor submits deployPending deploy requestThe generated YAML snapshot is stored on the request; agents do not receive it yet.
Approved deploy requestExecute succeedsDeployed with a new versionA new version is created from the reviewed request YAML snapshot, not from the current editor graph.
Approved deploy requestExecute fails without throwingApproved deploy requestThe request is reverted to approved so it can be retried.
Approved deploy requestExecute throwsApproved deploy requestThe request is reverted to approved and the caller receives a deploy failure.
Deployed pipelineUndeploy succeedsDraft and undeployedAgents stop receiving the pipeline on the next config poll.
Pipeline with historical versionsDeploy from version or rollback succeedsDeployed with a new versionA new latest version is created by copying the chosen historical version. History is preserved.

Invalid edges:

AttemptOutcome
Deploy a missing pipelineRejected as not found.
Deploy with invalid generated YAMLRejected; no version is created.
Deploy from a version that belongs to another pipelineRejected as a bad request.
Deploy from a missing historical versionRejected as not found.
Editor deploys from historical version in an approval-required environmentRejected; only admins can bypass approval for that path.
Agent poll after editor-only changesAgents still receive the last deployed version, not the edited graph.

Deploy request transitions

Deploy requests exist only when an environment requires approval and the requester does not have direct deploy authority.

FromEventToNotes
NoneEditor submits deployPendingThe request stores the reviewed YAML snapshot, changelog, and optional node selector.
PendingReviewer approvesApprovedThe claim is atomic: only a still-pending request can move to approved.
PendingReviewer rejectsRejectedTerminal. The review note is stored when provided.
PendingRequester cancelsCancelledTerminal. Only the requester can cancel while pending.
ApprovedDeploy executor claims requestDeployedThe claim is atomic: only a still-approved request can move to deployed.
ApprovedDeploy execution failsApprovedThe request is put back so a reviewer or operator can retry.
ApprovedDeploy-capable user cancelsCancelledTerminal.

Invalid edges:

AttemptOutcome
Create a second pending request for the same pipelineRejected as a conflict.
Approve a request that is not pendingRejected.
Approve your own request through the UI pathRejected.
Reject a request that is not pendingRejected.
Execute a request that is not approvedRejected.
Execute the same approved request twiceFirst atomic claim wins; later attempts are rejected.
Cancel a deployed, rejected, or already-cancelled requestRejected.

Agent config transitions

Agents poll for configuration after enrollment or after a push notification. Push is only a hint; the config poll is the source of truth.

Pipeline state at poll timeNode selector matchAgent receives
Draft or undeployedAnyNo pipeline config.
Deployed with no versionsAnyNo pipeline config.
Deployed with latest versionSelector absent or emptyLatest version snapshot.
Deployed with latest versionSelector matches node labelsLatest version snapshot.
Deployed with latest versionSelector does not match node labelsNo pipeline config.
Node in maintenance modeAnyNo pipeline config.

The config response is assembled from the immutable latest version. Secret and certificate references are resolved at poll time for built-in secret storage, so secret rotation can change the delivered checksum without creating a new pipeline version.

Invalid edges:

AttemptOutcome
Unauthenticated config pollRejected.
Poll for an environment that no longer existsRejected as not found.
Config snapshot cannot be parsed or resolved for one pipelineThat pipeline is skipped for the response; other pipelines can still be returned.
Node labels do not satisfy the pipeline selectorThe pipeline is omitted.

Heartbeat transitions

Agents report runtime status after applying config. The heartbeat path updates node health, node metadata, pipeline runtime rows, logs, metrics, and browser events.

FromHeartbeat inputTo
Any node statusAuthenticated heartbeatNode becomes healthy and last-seen timestamps update.
Previous node status is not healthyAuthenticated heartbeatA node status transition event is recorded and broadcast.
No node-pipeline status rowReported pipeline statusA row is inserted for that node and pipeline.
Existing node-pipeline status rowReported pipeline status changedThe row is updated and a pipeline status transition is broadcast.
Existing node-pipeline status rowPipeline omitted from heartbeatThe row is deleted for that node.

Invalid edges:

AttemptOutcome
Unauthenticated heartbeatRejected.
Malformed heartbeat bodyRejected.
Heartbeat reports a pipeline outside the node environmentThat pipeline status is ignored.
Heartbeat omits a previously reported pipelineThe server treats it as no longer running on that node and removes the status row.

Rollback

Rollback does not mutate a historical version. It creates a new latest version whose YAML, global config, nodes, and edges are copied from the chosen historical version. That means:

  • Rollback is auditable because the version number advances.
  • Agents receive rollback like any other deploy: by polling and receiving the new latest version.
  • Heartbeat status must still come from agents after they apply the rolled-back config.
  • A rollback target from another pipeline is invalid.

Concurrent deploy resolution

VectorFlow resolves concurrency with atomic state claims rather than long-running locks:

  • Pending deploy requests are unique by behavior: when creating a request, the server checks for an existing pending request inside a serializable transaction.
  • Approval claims only update requests that are still pending.
  • Execution claims only update requests that are still approved.
  • If two executors race, one moves the request to deployed and the other receives a rejection because the request is no longer approved.
  • If execution fails after the request was claimed, the request is reverted to approved so retry is explicit and visible.

These rules keep the deploy path idempotent at the workflow level: clients may retry after transport failures, but they must re-read request state before assuming another deploy should be started.

On this page