defmodule ArcadiaCloud.Sync.DropletsWorker do @moduledoc """ Full sync of DigitalOcean droplets. Idempotent: re-runs are no-ops absent state changes. Three-strike deletion for resources that vanish from N consecutive syncs. Tenant attribution is derived in two passes — phase 1 (this worker) tags all discovered resources to the `skyai-internal` project by default. Phase 1+ will resolve actual tenant projects via DO Projects API. """ use Oban.Worker, queue: :cloud_sync_full, max_attempts: 3 alias ArcadiaCloud.Cloud alias ArcadiaCloud.DigitalOcean.Client alias ArcadiaCloud.Sync.Bootstrap @kind "droplet" @provider "digitalocean" @impl Oban.Worker def perform(_job) do sync_started_at = DateTime.utc_now() |> DateTime.truncate(:second) with {:ok, _project} <- Bootstrap.ensure_skyai_internal(), {:ok, droplets} <- Client.list_droplets() do internal = Cloud.skyai_internal_project() Enum.each(droplets, fn d -> Cloud.upsert_resource(normalize(d, internal, sync_started_at)) end) Cloud.mark_stale(@kind, sync_started_at) :ok end end # ---- normalization -------------------------------------------------------- defp normalize(d, project, now) do %{ provider: @provider, provider_id: to_string(d["id"]), kind: @kind, name: d["name"], region: get_in(d, ["region", "slug"]), status: normalize_status(d["status"]), size_slug: d["size_slug"], cloud_project_id: project && project.id, tags: d["tags"] || [], attrs: %{ memory_mb: d["memory"], vcpus: d["vcpus"], disk_gb: d["disk"], image: take_image(d["image"]), networks: d["networks"], features: d["features"], do_created_at: d["created_at"] }, first_seen_at: now, last_seen_at: now } end defp normalize_status("active"), do: "active" defp normalize_status("off"), do: "off" defp normalize_status("new"), do: "provisioning" defp normalize_status("archive"), do: "archived" defp normalize_status(other) when is_binary(other), do: other defp normalize_status(_), do: "unknown" defp take_image(nil), do: nil defp take_image(image) when is_map(image) do Map.take(image, ["id", "name", "slug", "distribution"]) end end