fix(landing): short HTML edge TTL + host purge after production deploy (#6552)

* fix(landing): shorten HTML edge TTL and host-purge after production deploy

Long s-maxage=3600 + stale-while-revalidate=86400 left locale HTML
(/zh/pricing/, /de/pricing/, …) on different edge objects after
landing-page-production, so some languages looked deployed and others
did not. Cap HTML/edge docs at s-maxage=60 without multi-hour SWR, and
purge open-design.ai by hostname after pages deploy (token needs Zone
Cache Purge). Hashed _astro assets stay immutable.

* ci(landing): add manual host-purge workflow for edge cache recovery

Allows testing CLOUDFLARE_API_TOKEN Cache Purge permission and one-click
recovery without a full production rebuild. Production deploy still purges
after pages deploy.

* ci(landing): support purge-only production workflow mode

Lets us exercise CLOUDFLARE_API_TOKEN Cache Purge without a full rebuild,
and keeps host purge as a post-deploy job after a real promote.

* ci(landing): move edge-cache purge helper to workflow-owned TypeScript

pnpm guard rejects project-owned .mjs, so the new purge helper blocked
Validate workspace. Convert it to TypeScript and move it next to the other
landing workflow helpers under .github/scripts/, invoked with
--experimental-strip-types like landing-page-deploy-feishu.ts.

Also drop the purge-only production mode: blog-indexing-on-deploy listens on
successful landing-page-production runs and cannot tell a cache-only recovery
run from a real deploy. Purging without a rebuild already has a dedicated
entry point in landing-edge-cache-purge, so production purge now runs only
after a successful deploy.
This commit is contained in:
lefarcen
2026-08-13 14:46:04 +00:00
committed by GitHub
parent aab3be9174
commit dba64f2e45
5 changed files with 201 additions and 19 deletions
@@ -0,0 +1,41 @@
name: landing-edge-cache-purge
# Manual / test entry to host-purge open-design.ai (or staging) without a full
# production rebuild. Production deploy also purges after pages deploy; this
# workflow is for incident recovery and permission checks.
#
# Requires secrets.CLOUDFLARE_API_TOKEN with Zone → Cache Purge on the target
# zone. Optional: vars.CLOUDFLARE_ZONE_ID.
on:
workflow_dispatch:
inputs:
hosts:
description: 'Comma-separated hostnames to purge (no scheme)'
required: true
default: 'open-design.ai'
permissions:
contents: read
jobs:
purge:
name: Purge Cloudflare edge cache by hostname
if: github.repository == 'nexu-io/open-design'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
- name: Purge hosts
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ZONE_ID: ${{ vars.CLOUDFLARE_ZONE_ID }}
CLOUDFLARE_PURGE_HOSTS: ${{ inputs.hosts }}
run: node --experimental-strip-types .github/scripts/landing-page-purge-edge-cache.ts
+34 -1
View File
@@ -35,7 +35,9 @@ jobs:
# the main ref so a dispatch from a feature branch/tag is skipped outright
# (no deploy) instead of recording a non-main production run — which would
# also dodge blog-indexing's `workflow_run` `branches: [main]` filter.
if: github.repository == 'nexu-io/open-design' && github.ref == 'refs/heads/main'
if: >
github.repository == 'nexu-io/open-design'
&& github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 20
environment:
@@ -205,6 +207,37 @@ jobs:
--project-name=open-design-landing
--branch=main
# CF Pages deploy does not reliably invalidate custom-domain HTML across every
# POP when `_headers` allows edge caching. Purge by hostname so all locale
# paths (`/`, `/zh/pricing/`, …) drop together without purge_everything on
# the whole zone (keeps download.open-design.ai etc.).
# Token needs Zone → Cache Purge. Optional: set vars.CLOUDFLARE_ZONE_ID.
# Only runs after a real deploy. Purging without a rebuild (incident recovery,
# token permission check) belongs to the dedicated `landing-edge-cache-purge`
# workflow, so a cache-only run never reaches this workflow's `workflow_run`
# consumers (notably `blog-indexing-on-deploy`).
purge:
name: Purge open-design.ai edge cache (hosts)
needs: deploy
if: github.repository == 'nexu-io/open-design'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
- name: Purge open-design.ai edge cache (hosts)
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ZONE_ID: ${{ vars.CLOUDFLARE_ZONE_ID }}
CLOUDFLARE_PURGE_HOSTS: open-design.ai
run: node --experimental-strip-types .github/scripts/landing-page-purge-edge-cache.ts
# Post a Feishu card to the landing group once the promotion settles. Runs on
# BOTH success and failure (a failed production deploy is exactly when people
# need a ping), but only when `deploy` actually ran — a dispatch from a