You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+11
Original file line number
Diff line number
Diff line change
@@ -134,6 +134,7 @@ The IAM User that is used to run the action requires the following IAM permissio
134
134
"codedeploy:CreateDeployment",
135
135
"codedeploy:RegisterApplicationRevision",
136
136
"codedeploy:GetDeploymentConfig",
137
+
"codedeploy:GetDeploymentGroup",
137
138
"codedeploy:UpdateDeploymentGroup",
138
139
"codedeploy:CreateDeploymentGroup"
139
140
],
@@ -148,6 +149,16 @@ The IAM User that is used to run the action requires the following IAM permissio
148
149
}
149
150
```
150
151
152
+
## Race Conditions
153
+
154
+
As of writing, the AWS CodeDeploy API does not accept new deployment requests for an application and deployment group as long as another deployment is still in progress. So, this action will retry a few times and eventually (hopefully) succeed.
155
+
156
+
There might be situations where several workflow runs are triggered in quick succession - for example, when merging several approved pull requests in a short time. Since your test suites or workflow runs might take a varying amount of time to finish and to reach the deployment phase (_this_ action), you cannot be sure that the triggered deployments will happen in the order you merged the pull requests (to stick with the example). You could not even be sure that the last deployment made was based on the last commit in your repository.
157
+
158
+
To work around this, this action includes the GitHub Actions "[run id](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context)" in the `description` field for created deployments. Before creating a new deployment, it will fetch the _last attempted deployment_ from the AWS API and compare its run id with the current run. If the current run has a _lower_ id than the last attempted deployment, the deployment will be aborted.
159
+
160
+
This workaround should catch a good share of possible out-of-order deployments. There is a slight chance for mishaps, however: If a _newer_ deployment happens to start _after_ we checked the run id and finishes _before_ we commence our own deployment (just a few lines of code later), this might go unnoticed. To really prevent this from happening, ordering deployments probably needs to be supported on the AWS API side, see https://github.com/aws/aws-codedeploy-agent/issues/248.
core.setFailed(`🙅♂️ The last attempted deployment as returned by the AWS API has been created by a higher run number ${lastAttemptedDeploymentRunNumber}, this is run number ${runNumber}. Aborting.`);
91
+
return;
92
+
}else{
93
+
console.log(`🔎 Last attempted deployment was from run number ${lastAttemptedDeploymentRunNumber}, this is run number ${runNumber} - proceeding.`);
94
+
}
95
+
}
96
+
97
+
/*
98
+
There's a slight remaining chance that the above check does not suffice: If we just
99
+
passed the check, but another (newer) build creates AND finishes a deployment
100
+
BEFORE we reach the next lines, an out-of-order deployment might happen. This is a
101
+
race condition that requires an extension on the AWS API side in order to be resolved,
102
+
see https://github.com/aws/aws-codedeploy-agent/issues/248.
core.setFailed('🤥 Unable to create a new deployment (too much concurrency?)');
86
88
return;
87
89
}
88
90
91
+
if (runNumber) {
92
+
var {deploymentGroupInfo: {lastAttemptedDeployment: {deploymentId: lastAttemptedDeploymentId}}} = await codeDeploy.getDeploymentGroup({
93
+
applicationName: applicationName,
94
+
deploymentGroupName: deploymentGroupName,
95
+
}).promise();
96
+
97
+
var {deploymentInfo: {description: lastAttemptedDeploymentDescription}} = await codeDeploy.getDeployment({
98
+
deploymentId: lastAttemptedDeploymentId,
99
+
}).promise();
100
+
101
+
var matches, lastAttemptedDeploymentRunNumber;
102
+
103
+
if (matches = lastAttemptedDeploymentDescription.match(/run_number=(\d+)/)) {
104
+
lastAttemptedDeploymentRunNumber = matches[1];
105
+
if (parseInt(lastAttemptedDeploymentRunNumber) > parseInt(runNumber)) {
106
+
core.setFailed(`🙅♂️ The last attempted deployment as returned by the AWS API has been created by a higher run number ${lastAttemptedDeploymentRunNumber}, this is run number ${runNumber}. Aborting.`);
107
+
return;
108
+
} else {
109
+
console.log(`🔎 Last attempted deployment was from run number ${lastAttemptedDeploymentRunNumber}, this is run number ${runNumber} - proceeding.`);
110
+
}
111
+
}
112
+
113
+
/*
114
+
There's a slight remaining chance that the above check does not suffice: If we just
115
+
passed the check, but another (newer) build creates AND finishes a deployment
116
+
BEFORE we reach the next lines, an out-of-order deployment might happen. This is a
117
+
race condition that requires an extension on the AWS API side in order to be resolved,
118
+
see https://github.com/aws/aws-codedeploy-agent/issues/248.
119
+
*/
120
+
}
121
+
89
122
try {
90
123
var {deploymentId: deploymentId} = await codeDeploy.createDeployment({
91
124
...deploymentConfig,
92
125
...{
93
126
applicationName: applicationName,
94
127
deploymentGroupName: deploymentGroupName,
128
+
description: description,
95
129
revision: {
96
130
revisionType: 'GitHub',
97
131
gitHubLocation: {
@@ -157,8 +191,10 @@ exports.createDeployment = async function(applicationName, fullRepositoryName, b
0 commit comments