feat(ci): promote Trigger.dev tasks in lockstep with the ECS traffic cutover#5725
feat(ci): promote Trigger.dev tasks in lockstep with the ECS traffic cutover#5725TheodoreSpeaks wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview
New Reviewed by Cursor Bugbot for commit 30e1270. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 30e1270. Configure here.
| name: app-image-digest | ||
| path: digest/app-image-digest.txt | ||
| retention-days: 1 | ||
|
|
There was a problem hiding this comment.
ECS deploy before Trigger deploy
High Severity
promote-images only depends on migrate and build-amd64, not deploy-trigger-staging or deploy-trigger-production. It can retag ECR and start CodePipeline while the Trigger.dev skip-promotion deploy is still running or after it failed, so the app can cut over without a matching task version or with a long app–task skew.
Reviewed by Cursor Bugbot for commit 30e1270. Configure here.
| sleep "$POLL_INTERVAL" | ||
| fi | ||
| done | ||
| log "Matched pipeline execution: $EXECUTION_ID" |
There was a problem hiding this comment.
Stale pipeline digest match
Medium Severity
Phase A picks any pipeline execution whose ECR source revisionId equals the digest, using the first UUID returned. A prior completed run for the same image digest can match before the new execution exists, so AllowTraffic may already be Succeeded and Trigger.dev promotion runs immediately instead of waiting for this push’s cutover.
Reviewed by Cursor Bugbot for commit 30e1270. Configure here.
| EXECUTION_ID=$(aws codepipeline list-pipeline-executions \ | ||
| --pipeline-name "$PIPELINE" --max-items 30 \ | ||
| --query "pipelineExecutionSummaries[?sourceRevisions[?actionName=='ECR_Source' && revisionId=='$DIGEST']].pipelineExecutionId" \ | ||
| --output text 2>/dev/null | tr '\t ' '\n\n' | grep -Em1 '^[0-9a-f-]{36}$' || true) |
There was a problem hiding this comment.
Historical Deployment Satisfies Gate
When a previous deployment has the same image digest, this lookup can select that completed execution before the current tag push creates its execution. The old deployment already has a successful AllowTraffic, so the new Trigger.dev version is promoted before the current ECS cutover. Correlate the execution with this tag-promotion event, such as by requiring a start time after the retag, rather than accepting any historical digest match.
| target_id=$(aws deploy list-deployment-targets --deployment-id "$DEPLOYMENT_ID" \ | ||
| --query 'targetIds[0]' --output text 2>/dev/null || true) | ||
| at_status="" | ||
| if [ -n "$target_id" ] && [ "$target_id" != "None" ]; then | ||
| at_status=$(aws deploy get-deployment-target --deployment-id "$DEPLOYMENT_ID" --target-id "$target_id" \ | ||
| --query "deploymentTarget.ecsTarget.lifecycleEvents[?lifecycleEventName=='AllowTraffic'].status | [0]" \ | ||
| --output text 2>/dev/null || true) | ||
| if [ "$at_status" = "Succeeded" ]; then | ||
| log "Traffic cutover complete (AllowTraffic Succeeded) for $DEPLOYMENT_ID" |
There was a problem hiding this comment.
Only First Target Gates Promotion
When a CodeDeploy deployment contains multiple ECS targets, targetIds[0] can finish AllowTraffic while another target is still pending or has failed. The script then promotes Trigger.dev while part of the application remains on the old version. Require successful AllowTraffic for every returned ECS target before exiting.


Summary
--skip-promotionso new task runs keep executing the old version until we promote.promote-trigger-*job polls CodeDeploy (AllowTraffic) and then runstrigger promote, so tasks and app cut over in lockstep instead of tasks flipping ~4–50 min early (the prod bake queue).build-amd64publishes it as an artifact) → CodePipeline execution → CodeDeploy deployment id →AllowTraffic. ECR deploy tags are floating, so the digest is the only durable key.promote-images.promoted: when the stale-run guard skips the image retag, tasks correctly stay on the old version. If the app deploy fails or never cuts over, promote never fires and the job fails visibly..github/scripts/wait-for-ecs-cutover.shdoes the poll; verified end-to-end against real staging deploys (digest →d-…→AllowTraffic).Prerequisites before this runs on staging/prod
STAGING_AWS_ROLE_TO_ASSUME,AWS_ROLE_TO_ASSUME), which are managed outside the repo:codepipeline:ListPipelineExecutions/GetPipelineExecution/ListActionExecutions,codedeploy:GetDeployment/ListDeploymentTargets/GetDeploymentTarget.TRIGGER_ACCESS_TOKENrepo secret (a Trigger.dev PAT; spans all environments). Then disable the Trigger.dev git integration for staging/prod.Type of Change
Testing
wait-for-ecs-cutover.shagainst real completed staging deployments: correctly resolved digest → pipeline execution → CodeDeploy deployment →AllowTraffic(exit 0), and timed out cleanly on an unmatched digest (exit 1).actionlintclean (only pre-existing custom-runner-label warnings);bun run lintandbun run check:api-validation:strictpass; YAML validated.Checklist