Phase 4a: deployment-provisioning choreography saga

Wire a full tenant deployment as one orchestrated, compensating saga:
mark → create droplet → wait active → register in inventory → link to
deployment → point DNS → activate. A failure anywhere rolls the whole
thing back — droplet destroyed, DNS reverted, deployment moved to
cancelled.

- New lifecycle state `provisioning`; deployments created via the
  provision path enter here and only reach `active` once the saga's
  ActivateDeployment step runs.
- Four new steps: MarkDeploymentProvisioning (owns the deployment's
  failure state), LinkDeploymentResource, PointDeploymentDns,
  ActivateDeployment.
- Provisioning.provision_deployment/2 assembles + starts the saga.
- DeploymentController: POST /deployments with provision:true creates
  in `provisioning` and kicks the saga (202); GET /deployments/:id now
  returns the provisioning saga + per-step progress.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 20:44:49 +10:00
parent c10b847324
commit 29f4ad97d6
8 changed files with 480 additions and 8 deletions

View File

@@ -5,7 +5,7 @@ defmodule ArcadiaCloud.Deployments.CloudDeployment do
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
@states ~w(trial active past_due paused suspended cancelled archived)
@states ~w(provisioning trial active past_due paused suspended cancelled archived)
@llm_modes ~w(managed byo none)
def states, do: @states