Pulumi has a limitation when it comes to its AWSX Fragate service component as per these two issues:
If you have multiple ECS services, they will update one-by-one instead of in-parallel when continueBeforeSteadyState
flag is set to false
The flag is essential if you want your deployment build to actually fail when services aren't deployed successfully due to whatever reason
Disabling the flag will make everything update in-parallel but if one of the services is not healthy or rolled back then your CI will still not know
unless you build custom integrations with AWS EventBridge events
The following is a pulumi component resource that does what Pulumi should do by default and it behaves exactly as you would expect:
import { ECSClient, waitUntilServicesStable } from '@aws-sdk/client-ecs'
import * as pulumi from '@pulumi/pulumi'
export interface EcsAwaiterArgs {
/**
* The AWS region where the ECS cluster hosting the services should be awaited.
*/
awsRegion: pulumi.Input<string>
/**
* The name of the ECS cluster where the services should be awaited are located.
*/
ecsClusterName: pulumi.Input<string>
/**
* The names of the ECS services to await.
*/
ecsServiceNames: pulumi.Input<string>[]
waitTimeInSeconds: pulumi.Input<number>
}
export class EcsAwaiter extends pulumi.ComponentResource {
public readonly FinalResult: pulumi.Output<boolean>
constructor(
appName: string,
args: EcsAwaiterArgs,
opts?: pulumi.ComponentResourceOptions,
) {
super(`pulumi:backend:EcsAwaiter`, appName, {}, opts)
const allArgs = pulumi.all([
args.awsRegion,
args.ecsClusterName,
args.ecsServiceNames,
args.waitTimeInSeconds,
])
const waitResult = allArgs.apply(
async ([awsRegion, ecsClusterName, ecsServiceNames, waitTimeInSeconds]) => {
const ecsClient = new ECSClient({
region: awsRegion,
})
return await waitUntilServicesStable(
{
client: ecsClient,
maxWaitTime: waitTimeInSeconds,
},
{ cluster: ecsClusterName, services: ecsServiceNames },
)
},
)
this.FinalResult = waitResult.apply(resolvedWaitResult => {
if (resolvedWaitResult.state == 'SUCCESS') {
void pulumi.log.info('Services are stable')
return true
} else {
throw new Error('Services are not stable')
}
})
this.registerOutputs({
finalResult: this.FinalResult,
})
}
}