diff --git a/.github/workflows/publish-electric-image.yml b/.github/workflows/publish-electric-image.yml index 6eb57f20c3..34a4a36e73 100644 --- a/.github/workflows/publish-electric-image.yml +++ b/.github/workflows/publish-electric-image.yml @@ -2,7 +2,7 @@ name: Publish Electric image # Upstream's `electricsql/electric` Docker Hub repo was deleted (electric-sql/electric#4822), # which broke every PRD deploy at the Electric image build. This builds the same release -# from upstream source, once, into our own registry; `apps/electric/Dockerfile` pins the +# from upstream source, once, into our own registry; `ELECTRIC_IMAGE` in `apps/electric/alchemy.run.ts` pins the # resulting digest. Run it again only to adopt a new Electric version. on: @@ -91,7 +91,7 @@ jobs: { echo "Pushed \`${NAME}:${VERSION}@${DIGEST}\`" echo - echo "Built from electric-sql/electric@${UPSTREAM_SHA}. Pin it in apps/electric/Dockerfile:" + echo "Built from electric-sql/electric@${UPSTREAM_SHA}. Pin it as ELECTRIC_IMAGE in apps/electric/alchemy.run.ts:" echo - echo " FROM ${NAME}:${VERSION}@${DIGEST}" + echo " ${NAME}:${VERSION}@${DIGEST}" } >> "$GITHUB_STEP_SUMMARY" diff --git a/apps/electric/Dockerfile b/apps/electric/Dockerfile deleted file mode 100644 index bb8638b2f8..0000000000 --- a/apps/electric/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -# The upstream ElectricSQL sync service, unmodified. -# -# A Dockerfile rather than an image reference because alchemy's ECS service -# builds a context and pushes to ECR — so the task pulls from there over the -# VPC's S3 gateway endpoint, not from Docker Hub on every placement. -# -# PINNED, never `:latest`. `docker-compose.yml` tracks `:latest` locally on -# purpose, but here an upgrade is a deliberate read of the release notes: the -# storage format has changed across minors, and rolling back after the new -# version has rewritten the shape cache re-snapshots every connected client. -# -# Built from upstream source into our own registry by publish-electric-image.yml: -# upstream's Docker Hub repo was deleted (electric-sql/electric#4822). To upgrade, -# run that workflow with the new version and pin the digest from its summary. -FROM ghcr.io/mapletechlabs/maple/electric:1.7.12@sha256:d8a377eee0edeac0d4dbbd77c22b92c1ef601184722ea2b7da5b3381e3bb8e2c diff --git a/apps/electric/alchemy.run.ts b/apps/electric/alchemy.run.ts index 78042f67a2..c036f47823 100644 --- a/apps/electric/alchemy.run.ts +++ b/apps/electric/alchemy.run.ts @@ -1,4 +1,3 @@ -import { resolve } from "node:path" import * as AWS from "alchemy/AWS" import type * as Output from "alchemy/Output" import * as Effect from "effect/Effect" @@ -10,8 +9,15 @@ import { requiredPlain } from "@maple/infra/env" /** Port Electric's HTTP API binds (`ELECTRIC_PORT`, whose own default is 3000). */ const ELECTRIC_PORT = 3000 -/** Absolute: alchemy has changed how a relative `dockerfile` resolves between releases. */ -const DOCKERFILE = resolve("apps/electric/Dockerfile") +/** + * Upstream Electric, built into our registry by publish-electric-image.yml (upstream's Docker + * Hub repo was deleted, electric-sql/electric#4822). PINNED by digest: the shape cache format + * changes across minors, so an upgrade is a deliberate read of the release notes. Mirrored as an + * image ref, never built from a context: alchemy hashes a context together with `bun.lock`, so + * any unrelated dependency change would retag the image and restart this singleton. + */ +const ELECTRIC_IMAGE = + "ghcr.io/mapletechlabs/maple/electric:1.7.12@sha256:d8a377eee0edeac0d4dbbd77c22b92c1ef601184722ea2b7da5b3381e3bb8e2c" export interface CreateMapleElectricOptions extends Pick< MapleStackContext, @@ -114,8 +120,7 @@ export const createMapleElectric = ({ cluster, serviceName: name("electric"), - context: "apps/electric", - dockerfile: DOCKERFILE, + image: ELECTRIC_IMAGE, // Must match the image arch: a mismatch dies at start with `exec format error`. runtimePlatform: { cpuArchitecture: "ARM64", operatingSystemFamily: "LINUX" }, cpu: taskSize.cpu, diff --git a/docs/electric-sync.md b/docs/electric-sync.md index 3bc6f6347f..2aa4ba0da6 100644 --- a/docs/electric-sync.md +++ b/docs/electric-sync.md @@ -199,8 +199,11 @@ service runs `desiredCount: 1` with `minimumHealthyPercent: 0`: stop the old task, then start the new one. Every deploy therefore has a ~60s window with no sync. `/dashboards` degrades to its HTTP snapshot (`SyncDegradedBanner`), while the alerts lists have no fallback and sit in their retry state. This is why the -image tag is pinned in `apps/electric/Dockerfile` rather than tracking `:latest` -as local docker does. +image is pinned by digest (`ELECTRIC_IMAGE` in `apps/electric/alchemy.run.ts`) +rather than tracking `:latest` as local docker does, and why it is mirrored as an +image ref instead of built from a Dockerfile: alchemy hashes a build context +together with `bun.lock`, so any dependency bump retagged the image and restarted +Electric (two ~2 min gaps on 2026-10-14). ### Standing it up