@@ -203,7 +203,7 @@ async function tasksExitCode(ecs, clusterName, taskArns) {
203203}
204204
205205// Deploy to a service that uses the 'ECS' deployment controller
206- async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount, enableECSManagedTags, propagateTags, waitMaxDelaySeconds) {
206+ async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount, enableECSManagedTags, propagateTags, waitMaxDelaySeconds, beforeDeploymentId ) {
207207 core.debug('Updating the service');
208208
209209 const serviceManagedEBSVolumeName = core.getInput('service-managed-ebs-volume-name', { required: false }) || '';
@@ -238,7 +238,11 @@ async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForSe
238238 if (!isNaN(desiredCount) && desiredCount !== undefined) {
239239 params.desiredCount = desiredCount;
240240 }
241- await ecs.updateService(params);
241+ const updateResponse = await ecs.updateService(params);
242+
243+ // Extract the PRIMARY deployment ID from the update response
244+ const primaryDeployment = (updateResponse.service.deployments || []).find(d => d.status === 'PRIMARY');
245+ const afterDeploymentId = primaryDeployment ? primaryDeployment.id : null;
242246
243247 const region = await ecs.config.region();
244248 const consoleHostname = region.startsWith('cn') ? 'console.amazonaws.cn' : 'console.aws.amazon.com';
@@ -263,6 +267,36 @@ async function updateEcsService(ecs, clusterName, service, taskDefArn, waitForSe
263267 services: [service],
264268 cluster: clusterName
265269 });
270+
271+ // Verify the deployment was successful (not rolled back)
272+ if (afterDeploymentId && afterDeploymentId !== beforeDeploymentId) {
273+ core.debug('Verifying deployment succeeded after service stability...');
274+
275+ const verifyResponse = await ecs.describeServices({
276+ services: [service],
277+ cluster: clusterName
278+ });
279+
280+ const verifiedService = verifyResponse.services[0];
281+ const deployment = (verifiedService.deployments || []).find(d => d.id === afterDeploymentId);
282+
283+ if (!deployment) {
284+ throw new Error(
285+ `Deployment ${afterDeploymentId} not found after stabilization. ` +
286+ `The deployment was likely rolled back by the deployment circuit breaker.`
287+ );
288+ }
289+
290+ if (deployment.rolloutState === 'FAILED') {
291+ throw new Error(
292+ `Deployment ${afterDeploymentId} FAILED: ${deployment.rolloutStateReason || 'unknown reason'}`
293+ );
294+ }
295+
296+ core.info(`Deployment ${afterDeploymentId} verified: rolloutState=${deployment.rolloutState || 'N/A'}`);
297+ } else {
298+ core.debug('No new deployment was created by the update, skipping deployment verification');
299+ }
266300 } else {
267301 core.debug('Not waiting for the service to become stable');
268302 }
@@ -591,8 +625,11 @@ async function run() {
591625
592626 if (!serviceResponse.deploymentController || !serviceResponse.deploymentController.type || serviceResponse.deploymentController.type === 'ECS') {
593627 // Service uses the 'ECS' deployment controller, so we can call UpdateService
628+ const beforePrimaryDeployment = (serviceResponse.deployments || []).find(d => d.status === 'PRIMARY');
629+ const beforeDeploymentId = beforePrimaryDeployment ? beforePrimaryDeployment.id : null;
630+
594631 core.debug('Updating service...');
595- await updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount, enableECSManagedTags, propagateTags, waitMaxDelaySeconds);
632+ await updateEcsService(ecs, clusterName, service, taskDefArn, waitForService, waitForMinutes, forceNewDeployment, desiredCount, enableECSManagedTags, propagateTags, waitMaxDelaySeconds, beforeDeploymentId );
596633
597634 } else if (serviceResponse.deploymentController.type === 'CODE_DEPLOY') {
598635 // Service uses CodeDeploy, so we should start a CodeDeploy deployment
0 commit comments