From b0eefe41bef54e863d42763a28af3d7e2b966a2b Mon Sep 17 00:00:00 2001 From: Makisuo Date: Mon, 21 Sep 2026 20:07:27 +0200 Subject: [PATCH 1/3] chore(ingest): make the EC2 fleet the default so MAPLE_INGEST_FLEETS can go prd has run on EC2 alone since the 2026-09-21 cutover. An unset MAPLE_INGEST_FLEETS now means `ec2`, so the variable can be deleted from Infisical; setting it is only for bringing Fargate back beside EC2 or alone. Previews follow the same default, so the `preview:ingest-ec2` label and its workflow plumbing go, and the verify script targets the EC2 service unless the job asked for Fargate alone. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/deploy-pr-preview.yml | 3 --- packages/infra/src/aws/stage.test.ts | 10 +++++----- packages/infra/src/aws/stage.ts | 9 +++++---- scripts/ingest-preview-verify.sh | 10 +++++----- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/.github/workflows/deploy-pr-preview.yml b/.github/workflows/deploy-pr-preview.yml index b06a301419..139ee9956d 100644 --- a/.github/workflows/deploy-pr-preview.yml +++ b/.github/workflows/deploy-pr-preview.yml @@ -95,9 +95,6 @@ jobs: # Opt the preview into the in-VPC OTel collector (prd-only otherwise — # a cash-flow call, see `stageDeploysCollector`). MAPLE_DEPLOY_AWS_COLLECTOR: ${{ contains(github.event.pull_request.labels.*.name, 'preview:collector') && '1' || '' }} - # Run the preview's gateway on the EC2 fleet (NVMe WAL, host - # networking) instead of Fargate — see `parseIngestFleets`. - MAPLE_INGEST_FLEETS: ${{ contains(github.event.pull_request.labels.*.name, 'preview:ingest-ec2') && 'ec2' || '' }} PR_NUMBER: ${{ github.event.pull_request.number }} PR_BRANCH: ${{ github.head_ref }} # Stamped onto deployed telemetry as `vcs.ref.head.revision`. Use the PR diff --git a/packages/infra/src/aws/stage.test.ts b/packages/infra/src/aws/stage.test.ts index f71bd830fa..a007befd64 100644 --- a/packages/infra/src/aws/stage.test.ts +++ b/packages/infra/src/aws/stage.test.ts @@ -129,14 +129,14 @@ describe("resolveIngestScaling", () => { }) describe("parseIngestFleets", () => { - it("is Fargate only when unset", () => { - expect(parseIngestFleets(undefined)).toEqual({ fargate: true, ec2: false }) - expect(parseIngestFleets("")).toEqual({ fargate: true, ec2: false }) + it("is EC2 only when unset", () => { + expect(parseIngestFleets(undefined)).toEqual({ fargate: false, ec2: true }) + expect(parseIngestFleets("")).toEqual({ fargate: false, ec2: true }) }) - it("runs both fleets during the cutover", () => { + it("can bring Fargate back beside EC2, or alone", () => { expect(parseIngestFleets("fargate, ec2")).toEqual({ fargate: true, ec2: true }) - expect(parseIngestFleets("ec2")).toEqual({ fargate: false, ec2: true }) + expect(parseIngestFleets("fargate")).toEqual({ fargate: true, ec2: false }) }) it("rejects a fleet it does not know rather than deploying neither", () => { diff --git a/packages/infra/src/aws/stage.ts b/packages/infra/src/aws/stage.ts index f0b2c49355..45383bab83 100644 --- a/packages/infra/src/aws/stage.ts +++ b/packages/infra/src/aws/stage.ts @@ -155,8 +155,8 @@ export function resolveIngestTaskSize(stage: MapleStage): IngestTaskSize { /** * Which fleets run the gateway. Both can run at once, each behind its own ALB, - * which is how the Fargate → EC2 cutover works: bring EC2 up beside Fargate, - * flip the proxied `ingest` CNAME, then drop Fargate. + * which is how a fleet cutover works: bring the new one up beside the old, + * flip the proxied `ingest` CNAME, then drop the old one. */ export interface IngestFleets { fargate: boolean @@ -165,14 +165,15 @@ export interface IngestFleets { /** * Parses `MAPLE_INGEST_FLEETS` (`fargate`, `ec2`, or `fargate,ec2`). Unset is - * Fargate only, the state before the cutover. + * EC2 only, where prd has run since the 2026-09-21 cutover; the variable is + * only set to bring Fargate back beside it. */ export function parseIngestFleets(value: string | undefined): IngestFleets { const requested = (value ?? "") .split(",") .map((fleet) => fleet.trim()) .filter((fleet) => fleet !== "") - if (requested.length === 0) return { fargate: true, ec2: false } + if (requested.length === 0) return { fargate: false, ec2: true } const unknown = requested.filter((fleet) => fleet !== "fargate" && fleet !== "ec2") if (unknown.length > 0) { throw new Error( diff --git a/scripts/ingest-preview-verify.sh b/scripts/ingest-preview-verify.sh index 4d5ae119be..bfa1c02c32 100755 --- a/scripts/ingest-preview-verify.sh +++ b/scripts/ingest-preview-verify.sh @@ -15,12 +15,12 @@ set -euo pipefail : "${PR_NUMBER:?PR_NUMBER is required}" region="${AWS_REGION:-us-east-1}" cluster="maple-ingest-pr-${PR_NUMBER}" -# The EC2 fleet (`preview:ingest-ec2`) is its own ECS service beside where -# the Fargate one would be; the job's MAPLE_INGEST_FLEETS says which ran. -if [[ "${MAPLE_INGEST_FLEETS:-}" == "ec2" ]]; then - gateway_service="maple-ingest-ec2-pr-${PR_NUMBER}" -else +# Each fleet is its own ECS service. EC2 is the default (`parseIngestFleets`); +# only a job that set MAPLE_INGEST_FLEETS to Fargate alone runs the other one. +if [[ "${MAPLE_INGEST_FLEETS:-}" == "fargate" ]]; then gateway_service="maple-ingest-pr-${PR_NUMBER}" +else + gateway_service="maple-ingest-ec2-pr-${PR_NUMBER}" fi collector_service="maple-otel-collector-pr-${PR_NUMBER}" namespace="maple-ingest-pr-${PR_NUMBER}.internal" From e5289192701b4addf3fa61fc13d44c9c93573a61 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Mon, 21 Sep 2026 20:11:05 +0200 Subject: [PATCH 2/3] fix(previews): build the alchemy deps before a destroy too `alchemy:destroy:pr` skipped `alchemy:build-deps`, so every PR teardown since the stack started importing `@maple-dev/alchemy/telemetry` died on "Cannot find package" before touching a resource, and closed previews kept their VPC, ALB and hosts. The orphan sweep only covers Cloudflare, so nothing caught it. PR #937's stack was still running an hour after the merge. Co-Authored-By: Claude Fable 5.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 86daa24ac6..29f005c37c 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,8 @@ "alchemy:deploy": "bun run alchemy:build-deps && alchemy deploy --yes", "alchemy:deploy:prd": "bun run alchemy:build-deps && alchemy deploy --yes --adopt --stage prd", "alchemy:deploy:pr": "bun run alchemy:build-deps && alchemy deploy --yes --adopt --stage pr-${PR_NUMBER}", - "alchemy:destroy": "alchemy destroy --yes", - "alchemy:destroy:pr": "alchemy destroy --yes --stage pr-${PR_NUMBER}", + "alchemy:destroy": "bun run alchemy:build-deps && alchemy destroy --yes", + "alchemy:destroy:pr": "bun run alchemy:build-deps && alchemy destroy --yes --stage pr-${PR_NUMBER}", "test": "turbo test", "tinybird:manifest": "bun run ./scripts/generate-tinybird-project-manifest.ts", "tinybird:manifest:check": "bun run ./scripts/generate-tinybird-project-manifest.ts --check", From 74d586afd8fae20ed88ae9d65df44a6f01b16a3e Mon Sep 17 00:00:00 2001 From: Makisuo Date: Mon, 21 Sep 2026 20:12:35 +0200 Subject: [PATCH 3/3] fix(previews): parse MAPLE_INGEST_FLEETS in the verify script like the deploy does Whitespace and comma membership, so a padded or combined value picks the same service the stack actually ran. Co-Authored-By: Claude Fable 5.1 --- scripts/ingest-preview-verify.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/ingest-preview-verify.sh b/scripts/ingest-preview-verify.sh index bfa1c02c32..5eb7bda0c6 100755 --- a/scripts/ingest-preview-verify.sh +++ b/scripts/ingest-preview-verify.sh @@ -17,7 +17,10 @@ region="${AWS_REGION:-us-east-1}" cluster="maple-ingest-pr-${PR_NUMBER}" # Each fleet is its own ECS service. EC2 is the default (`parseIngestFleets`); # only a job that set MAPLE_INGEST_FLEETS to Fargate alone runs the other one. -if [[ "${MAPLE_INGEST_FLEETS:-}" == "fargate" ]]; then +# Same parsing as the deploy: whitespace ignored, comma-separated membership. +fleets=",${MAPLE_INGEST_FLEETS:-}," +fleets="${fleets//[[:space:]]/}" +if [[ "$fleets" == *",fargate,"* && "$fleets" != *",ec2,"* ]]; then gateway_service="maple-ingest-pr-${PR_NUMBER}" else gateway_service="maple-ingest-ec2-pr-${PR_NUMBER}"