Skip to content

Commit 9ac9bfa

Browse files
heiskrCopilot
andauthored
Hard-purge Fastly + consolidate purge scripts into one workflow (#61810)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f949ea3 commit 9ac9bfa

10 files changed

Lines changed: 369 additions & 380 deletions

.github/workflows/index-general-search.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,7 @@ jobs:
231231
env:
232232
FASTLY_TOKEN: ${{ secrets.FASTLY_TOKEN }}
233233
FASTLY_SERVICE_ID: ${{ secrets.FASTLY_SERVICE_ID }}
234-
FASTLY_SURROGATE_KEY: api-search:${{ matrix.language }}
235-
run: npm run purge-fastly-edge-cache
234+
run: npm run purge-fastly -- --surrogate-key api-search:${{ matrix.language }}
236235

237236
- name: Upload failures artifact
238237
if: ${{ steps.check-failures.outputs.has_failures == 'true' }}

.github/workflows/purge-fastly-all.yml

Lines changed: 0 additions & 44 deletions
This file was deleted.

.github/workflows/purge-fastly.yml

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,50 @@
11
name: Purge Fastly
22

3-
# **What it does**: Sends a soft-purge to Fastly.
4-
# **Why we have it**: So that, right after a production deploy, we start afresh
5-
# **Who does it impact**: Writers and engineers.
3+
# **What it does**: Purges Fastly after a deploy and on demand. Soft purge by
4+
# default; can hard purge specific languages, or hard purge the ENTIRE cache.
5+
# **Why we have it**: So that, right after a production deploy, we start afresh,
6+
# and so docs engineering can clear a bad cache state without the Fastly UI.
7+
# **Who does it impact**: Writers and engineers. A full purge impacts all readers,
8+
# origin sees a traffic spike while the cache refills, so it's gated below.
69

710
on:
811
deployment_status:
912
workflow_dispatch:
1013
inputs:
1114
languages:
12-
description: "Comma separated languages. E.g. 'en,es,ja,pt,zh,ru,fr,ko,de' (defaults to en)"
15+
description: "Comma separated languages, e.g. 'en,es,ja,pt,zh,ru,fr,ko,de'. Blank = all languages."
1316
required: false
14-
default: 'en' # Temporary, only purge English on deploy. Set to empty string for all
17+
default: 'en'
18+
hard:
19+
description: 'Evict immediately instead of the default soft purge. Use when a soft purge fails to clear stale content.'
20+
type: boolean
21+
required: false
22+
default: false
23+
everything:
24+
description: 'DANGER: hard-purge the ENTIRE Fastly cache... every key, all readers. Ignores the language/hard inputs. To confirm, type exactly: "purge everything". Otherwise leave blank.'
25+
required: false
26+
default: ''
1527

1628
permissions:
1729
contents: read
1830

31+
# Serialize full-cache purges so two can't overlap and leave the cache in an
32+
# unknown state. Every other run (per-deploy, per-language) gets a unique group
33+
# so those never block each other.
34+
concurrency:
35+
group: ${{ (inputs.everything == 'purge everything' && 'purge-fastly-all') || format('purge-fastly-{0}', github.run_id) }}
36+
cancel-in-progress: false
37+
1938
env:
2039
FASTLY_TOKEN: ${{ secrets.FASTLY_TOKEN }}
2140
FASTLY_SERVICE_ID: ${{ secrets.FASTLY_SERVICE_ID }}
2241

2342
jobs:
2443
send-purges:
25-
# Run when workflow_dispatch is the event (manual) or when deployment_status is the event (automatic) and it's a successful production deploy.
26-
# NOTE: This workflow triggers on all deployment_status events (including staging), but only runs for production.
44+
# Run when workflow_dispatch is the event
45+
# or when deployment_status is the event and it's a successful production deploy.
46+
# NOTE: This workflow triggers on all deployment_status events,
47+
# including staging, but only runs for production.
2748
# Non-production deploys will show as "skipped" - this is expected behavior.
2849
if: >-
2950
${{
@@ -38,52 +59,50 @@ jobs:
3859

3960
- uses: ./.github/actions/node-npm-setup
4061

41-
- name: Wait for production to match build commit SHA
42-
if: github.event_name != 'workflow_dispatch'
43-
# A single /_build match only proves *one* Moda instance is serving the
44-
# new build; others can still be mid-rollout. If we purge then, Fastly's
45-
# soft purge serves stale-while-revalidate and may revalidate against a
46-
# lagging instance, re-caching old content as fresh for a full TTL. So we
47-
# require several consecutive matches to confirm the rollout has settled
48-
# across instances before purging.
62+
- name: Validate confirmation input
63+
# A full-cache purge only triggers on the exact string "purge everything".
64+
# Any other non-empty value (e.g. a typo) would otherwise be silently
65+
# ignored and fall through to a normal soft purge that finishes green, so
66+
# an operator could think they evicted the whole cache when they didn't.
67+
# Fail loudly instead.
68+
env:
69+
EVERYTHING_INPUT: ${{ inputs.everything }}
4970
run: |
50-
needs=$(git rev-parse HEAD)
51-
start_time=$(date +%s)
52-
timeout_seconds=1200
53-
required_matches=5
54-
interval_seconds=10
55-
consecutive=0
56-
while [[ $consecutive -lt $required_matches ]]
57-
do
58-
if [[ $(($(date +%s) - $start_time)) -gt $timeout_seconds ]]
59-
then
60-
echo "Production did not reach $required_matches consecutive build matches within $timeout_seconds seconds"
61-
exit 1
62-
fi
63-
if [[ $needs == $(curl -s --fail --retry-connrefused --retry 5 https://docs.github.com/_build) ]]
64-
then
65-
consecutive=$((consecutive + 1))
66-
echo "Production matches the build commit ($consecutive/$required_matches)"
67-
else
68-
if [[ $consecutive -gt 0 ]]
69-
then
70-
echo "Production stopped matching the build commit; resetting consecutive count"
71-
else
72-
echo "Production is not up to date with the build commit"
73-
fi
74-
consecutive=0
75-
fi
76-
if [[ $consecutive -lt $required_matches ]]
77-
then
78-
sleep $interval_seconds
79-
fi
80-
done
81-
echo "Production is up to date with the build commit ($required_matches consecutive matches)"
71+
if [ -n "$EVERYTHING_INPUT" ] && [ "$EVERYTHING_INPUT" != "purge everything" ]; then
72+
echo "::error::To purge the entire cache, the 'everything' input must be exactly 'purge everything'. Got: '$EVERYTHING_INPUT'. Leave it blank for a normal purge."
73+
exit 1
74+
fi
8275
83-
- name: Purge Fastly edge cache per language
76+
- name: Purge Fastly
77+
# Auto post-deploy runs wait for the build, purge English only (temporary),
78+
# and stay soft. A manual run uses the inputs: blank languages = all, the
79+
# `hard` toggle, or a confirmed full-cache purge.
80+
#
81+
# Raw inputs are passed through the environment and quoted, never spliced
82+
# into the command string, so a value like `en' --everything` can't break
83+
# out of its argument and inject another flag.
8484
env:
85-
LANGUAGES: ${{ inputs.languages || 'en' }} # Temporary, only purge English on deploy. Set to empty string for all
86-
run: npm run purge-fastly-edge-cache-per-language
85+
EVENT_NAME: ${{ github.event_name }}
86+
LANGUAGES_INPUT: ${{ inputs.languages }}
87+
HARD_INPUT: ${{ inputs.hard }}
88+
EVERYTHING_INPUT: ${{ inputs.everything }}
89+
run: |
90+
args=()
91+
if [ "$EVENT_NAME" != "workflow_dispatch" ]; then
92+
args+=(--wait-for-build)
93+
fi
94+
if [ "$EVENT_NAME" = "deployment_status" ]; then
95+
args+=(--languages en)
96+
elif [ -n "$LANGUAGES_INPUT" ]; then
97+
args+=(--languages "$LANGUAGES_INPUT")
98+
fi
99+
if [ "$HARD_INPUT" = "true" ]; then
100+
args+=(--hard)
101+
fi
102+
if [ "$EVERYTHING_INPUT" = "purge everything" ]; then
103+
args+=(--everything)
104+
fi
105+
npm run purge-fastly -- "${args[@]}"
87106
88107
- uses: ./.github/actions/slack-alert
89108
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,7 @@
7979
"prettier": "prettier -w \"**/*.{ts,tsx,scss,yml,yaml}\"",
8080
"prettier-check": "prettier -c \"**/*.{ts,tsx,scss,yml,yaml}\"",
8181
"prevent-pushes-to-main": "tsx src/workflows/prevent-pushes-to-main.ts",
82-
"purge-fastly-edge-cache": "tsx src/workflows/purge-fastly-edge-cache.ts",
83-
"purge-fastly-edge-cache-per-language": "tsx src/languages/scripts/purge-fastly-edge-cache-per-language.ts",
84-
"purge-fastly-all": "tsx src/workflows/purge-fastly-all.ts",
82+
"purge-fastly": "tsx src/workflows/purge-fastly.ts",
8583
"readability-report": "tsx src/workflows/experimental/readability-report.ts",
8684
"ready-for-docs-review": "tsx src/workflows/ready-for-docs-review.ts",
8785
"release-banner": "tsx src/ghes-releases/scripts/release-banner.ts",

src/languages/scripts/purge-fastly-edge-cache-per-language.ts

Lines changed: 0 additions & 131 deletions
This file was deleted.

src/workflows/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Scripts are registered in `package.json`:
2626
| check-content-type | `npm run check-content-type` | Validates content types |
2727
| delete-orphan-translation-files | `npm run delete-orphan-translation-files` | Removes orphaned translations |
2828
| enable-automerge | `npm run enable-automerge` | Enables PR automerge |
29-
| purge-fastly-edge-cache | `npm run purge-fastly-edge-cache` | Purges Fastly CDN cache |
29+
| purge-fastly | `npm run purge-fastly` | Purges Fastly CDN cache (per-language, single-key, or entire cache) |
3030
| prevent-pushes-to-main | (Husky hook) | Prevents pushing to main |
3131

3232
### Running tests

0 commit comments

Comments
 (0)