Skip to content

Commit c9c93af

Browse files
authored
Merge pull request #6 from NarrativeScience/QPT-31289/py2sfn-deploy-fix
QPT-31289/py2sfn-deploy-fix
2 parents 62c2e91 + dd14185 commit c9c93af

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Manage workflow concurrency and job state using an external store.
66

77
This orb allows you to:
88

9-
- Limit the number of concurrently running workflows. This is useful when you want to only deploy one batch of changes at a time or use AWS CloudFormation and need to wait for the previous deploy to finish.
9+
- Limit the number of concurrently running workflows. This is useful when you want to only allow one batch of changes at a time or use AWS CloudFormation and need to wait for the previous deploy to finish.
1010
- Squash commits that are deployed in a workflow when the workflow is allowed to proceed
1111
- Store and retreive data from a key-value store in jobs, even if they're run in parallel
1212
- Track the status of a workflow from the command line
@@ -98,7 +98,7 @@ username | string | GitHub username of commit author
9898
workflow_id | string | Workflow instance ID
9999
status | string | Localized secondary index. One of `QUEUED`, `RUNNING`, `SUCCESS`, `FAILED`. Starts out as `QUEUED`.
100100

101-
The job then starts polling the table for the oldest item that doesn't have a status attribute of `SUCCESS` or `FAILED`. If that item has the same `workflow_id` as the job, that means the job is at the "front" of the queue and can continue; we set the item's status to `RUNNING` and the workflow transitions to the next job. It will wait in the queue for up to 4 hours before failing. When the workflow is allowed to continue, it can be said to have a "lock" on the deploy.
101+
The job then starts polling the table for the oldest item that doesn't have a status attribute of `SUCCESS` or `FAILED`. If that item has the same `workflow_id` as the job, that means the job is at the "front" of the queue and can continue; we set the item's status to `RUNNING` and the workflow transitions to the next job. It will wait in the queue for up to 4 hours before failing. When the workflow is allowed to continue, it can be said to have a "lock".
102102

103103
### Exiting the Queue: `exit-queue`
104104

@@ -134,9 +134,9 @@ The deploy worklow has the capability to "squash commits", which replicates a fe
134134

135135
__Why?__ The primary goal of this is to reduce the time it takes for developers to get their merged code into production. A secondary goal is to reduce the cost of a bunch of containers burning CircleCI credits while trying to acquire a lock on the workflow.
136136

137-
__How does it work?__ When you merge, your commit [enters the queue](#entering-the-queue). However, if someone else merges and your commit is still waiting to proceed, it will detect that it's no longer the HEAD commit of the master branch and self-cancel. Since we build and deploy everything during the workflow, your changes will be included when that later commit starts running. Once a workflow passes the `wait-in-queue` job, it is considered to be in the "running" state and will not be squashed.
137+
__How does it work?__ When you merge, your commit [enters the queue](#entering-the-queue). However, if someone else merges and your commit is still waiting to proceed, it will detect that it's no longer last in the queue and self-cancel. Since we build and deploy everything during the workflow, your changes will be included when that later commit starts running. Once a workflow passes the `wait-in-queue` job, it is considered to be in the "running" state and will not be squashed.
138138

139-
__What if I don't want my commit squashed?__ If you don't want this behavior for whatever reason, you can include the tag `[force deploy]` in your merged commit message.
139+
__What if I don't want my commit squashed?__ There are known cases in which a commit should not be squashed, in these cases add `[force deploy]` in your merged commit message. This is most common when a commit has database migrations included or the workflow has specific conditions that require commits to be executed without being squashed.
140140

141141
__Note:__ As of now, if there's a failure in the deploy workflow, the Slack message sent to the channel will only include the author of that commit, i.e. it won't contain the list of authors of commits that were squashed. We can see how it plays out before deciding if this behavior should be added.
142142

src/commands/wait-in-queue.yml

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ steps:
6565
mkdir -p /tmp/workspace
6666
echo "$WORKFLOW_KEY" > /tmp/workspace/workflow-key.json
6767
68-
PREV_COMMIT="$(git rev-parse HEAD^)"
68+
PREV_COMMIT="$(git rev-parse $CIRCLE_SHA1^)"
6969
7070
# Create a temporary file containing the new item value (JSON)
7171
ITEM="$(mktemp)"
@@ -87,6 +87,7 @@ steps:
8787
aws dynamodb put-item \
8888
--table-name "$DYNAMODB_TABLE_WORKFLOWS" \
8989
--item "file://$ITEM"
90+
echo "Added commit ($CIRCLE_SHA1) to the queue"
9091
9192
# Query the table to find the workflow with the single oldest committed_at
9293
# timestamp and with a status of running or queued
@@ -99,8 +100,7 @@ steps:
99100
--key-condition-expression '#key = :key' \
100101
--filter-expression '#status IN (:running, :queued)' \
101102
--expression-attribute-names '{"#key": "key", "#status": "status"}' \
102-
--expression-attribute-values "$values" \
103-
--max-items 1
103+
--expression-attribute-values "$values"
104104
}
105105
106106
function workflowForCommitExists() {
@@ -147,6 +147,7 @@ steps:
147147
# in the correct order.
148148
if [[ -n "$CHECK_PREVIOUS_COMMIT" ]]; then
149149
if ! workflowForCommitExists "$PREV_COMMIT"; then
150+
echo "The previous commit: $PREV_COMMIT was not found! Will wait for $PREV_COMMIT to deploy"
150151
exit 1
151152
fi
152153
fi
@@ -168,6 +169,34 @@ steps:
168169
)
169170
}
170171
172+
# Check if this workflow is at the end of the queue
173+
function isWorkflowEndOfQueue() {
174+
(
175+
# Check to see if this commit is at the end of the queue or if another
176+
# commit is pending that will deploy these changes.
177+
178+
local result="$(queryItems)"
179+
if [[ $? -ne 0 ]]; then
180+
echo "Failed to query for workflow items"
181+
exit 1
182+
fi
183+
184+
# Get the last workflow_id in the queue
185+
local workflow_id="$(echo "$result" | jq -r .Items[-1].workflow_id.S -)"
186+
local count="$(echo "$result" | jq -r .Count -)"
187+
echo "There are $count items (including this one) currently in the queue"
188+
189+
if [[ "$workflow_id" == "$CIRCLE_WORKFLOW_ID" || "$count" == 0 ]]; then
190+
echo "This workflow ($CIRCLE_WORKFLOW_ID) is the last in the queue."
191+
exit 0
192+
else
193+
echo "This workflow ($CIRCLE_WORKFLOW_ID) is not at the end of the queue. Last Commit in the Queue is:"
194+
echo "$(echo "$result" | jq .Items[-1] -)"
195+
exit 1
196+
fi
197+
)
198+
}
199+
171200
# Check if the commit is still the HEAD of the branch
172201
function isCommitHeadOfBranch() {
173202
(
@@ -191,6 +220,8 @@ steps:
191220
shopt -s nocasematch
192221
if [[ "$MESSAGE" == *'<< parameters.do_not_cancel_workflow_if_tag_in_commit >>'* ]]; then
193222
SKIP_COMMIT_ALLOWED=0
223+
echo "Skip is disabled"
224+
echo "This Commit ($CIRCLE_SHA1) will not self-cancel and run until it acquires the lock or times out"
194225
fi
195226
shopt -u nocasematch
196227
<</ parameters.do_not_cancel_workflow_if_tag_in_commit >>
@@ -223,18 +254,30 @@ steps:
223254
echo "Attempt: $n of $MAX_ATTEMPTS"
224255
225256
if [[ "$SKIP_COMMIT_ALLOWED" == 1 ]]; then
226-
if isCommitHeadOfBranch; then
227-
echo "Commit $CIRCLE_SHA1 is still HEAD of the $CIRCLE_BRANCH branch"
257+
# If this is not the last commit, then cancel
258+
if isWorkflowEndOfQueue; then
259+
echo "This commit ($CIRCLE_SHA1) is last in the queue; Waiting to acquire the lock"
228260
else
229261
echo 'export CANCEL_JOB=1' >> $BASH_ENV
230262
echo 'export WORKFLOW_LOCK_BUILD_STATUS=CANCELLED' >> $BASH_ENV
231-
echo "Commit $CIRCLE_SHA1 is no longer HEAD of the $CIRCLE_BRANCH branch and will be skipped"
263+
echo "A newer commit has been added to the queue and is expected to contain these changes"
264+
echo "This workflow ($CIRCLE_WORKFLOW_ID) will self-cancel and the commit ($CIRCLE_SHA1) will be squashed into the next"
232265
exit 0
233266
fi
234267
fi
235268
236269
if isWorkflowFrontOfQueue; then
237270
updateWorkflowStatus
271+
echo "This commit ($CIRCLE_SHA1) has acquired the lock"
272+
273+
# Check if this is the head of the branch just to notify the user
274+
if isCommitHeadOfBranch; then
275+
echo "$CIRCLE_SHA1 is the head of $CIRCLE_BRANCH"
276+
else
277+
echo "$CIRCLE_SHA1 is NOT the head of $CIRCLE_BRANCH."
278+
echo "This is okay and could be the case if squashing is disabled or your pipeline filters out some commits."
279+
fi
280+
238281
exit 0
239282
fi
240283

0 commit comments

Comments
 (0)