Loco Deployment State Machine
sparki intermediate 5 min read
ELI5
A deployment row in PostgreSQL has two state knobs — status and current_phase. The API combines them into one human-friendly word (queued, validating, deploying, healthy, failed, rolled_back) so callers don’t have to learn the internal taxonomy.
Technical Deep Dive
services/deploy-loco/src/models/deployment.rs ships DeploymentRow (DB shape) and DeploymentResponse (API shape). The translation lives in DeploymentRow::api_status. The Go side (subsystems/loco/types.go) carries a parallel enum used for engine-side bookkeeping.
DB Status Values (loco subsystem types.go)
| Constant | String |
|---|---|
StatusPending | pending |
StatusValidating | validating |
StatusDeploying | deploying |
StatusHealthCheck | health_check |
StatusSuccess | success |
StatusFailed | failed |
StatusRolledBack | rolled_back |
StatusCanceled | canceled |
API Status Translation
match (status, current_phase) { ("pending", Some("queued")) => "queued", ("pending", Some("validating")) => "validating", ("deploying", _) => "deploying", ("success", _) => "healthy", ("failed", _) => "failed", ("rolled_back", _) => "rolled_back", _ => status.clone(),}State Diagram
stateDiagram-v2 [*] --> pending_queued: row insert pending_queued --> pending_validating: pre-flight starts pending_validating --> deploying: validation passes pending_validating --> failed: validation rejects deploying --> health_check: platform reports rollout done health_check --> success: probes green health_check --> failed: probes red success --> rolled_back: manual rollback issued failed --> rolled_back: auto rollback deploying --> canceled: user cancel pending_queued --> canceled: user cancel success --> [*] failed --> [*] rolled_back --> [*] canceled --> [*]Class Diagram
classDiagram class DeploymentRow { +Uuid id +Uuid project_id +Option~Uuid~ build_id +String environment +String status +Option~String~ current_phase +Option~String~ platform +Option~String~ deployment_url +Option~String~ health_check_status +Option~Uuid~ rollback_target_id +Option~i32~ attempts +Option~DateTime~ next_attempt_at +api_status() String +to_response() DeploymentResponse } class DeploymentResponse { +Uuid id +String environment +Option~String~ strategy +String status +Option~String~ current_phase +Option~String~ deployment_url +Option~String~ health_check_status } DeploymentRow --> DeploymentResponse : "api_status()"Why Two Fields
status is coarse (workflow state) and current_phase is fine-grained sub-state. Splitting them keeps the SQL filter cheap (index on status) while preserving the detail the dashboard needs. The API merges them so external callers do not have to JOIN the meaning.
Key Terms
- status → coarse SQL-indexable workflow state column
- current_phase → sub-state used to disambiguate
pending(queued vs validating) - api_status → method that flattens the two columns to one string for the response
- rollback_target_id → FK to the deployment this one rolled back to (nullable)
Q&A
Q: Why does API show healthy instead of success?
A: Operators reading a dashboard care about service health, not job-completion semantics. The translation is one place — api_status() — so renaming is a one-line change.
Q: When does rolled_back appear?
A: When a deployment that previously reached success (or failed with auto-rollback) has status flipped to rolled_back and rollback_target_id populated to point at the previous good deployment.
Q: Are attempts and next_attempt_at part of the API response?
A: No — they are internal scheduling fields used by the deploy-loco worker to retry. Only the columns listed in DeploymentResponse are exposed.
Examples
A web-app polling GET /deployments/:id while a Railway deploy progresses sees: queued → validating → deploying → healthy (terminal). Behind the scenes the row went pending+queued → pending+validating → deploying+rolling → success+null.
neighbors on the map
- Site Hosting Modes & Lifecycle Stages adding a new fork branching on platform vs user_git
- Site Provisioning Saga State Machine debugging a site stuck mid-provision
- Run Outcome Classification interpreting a History row's status pill