This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-website.git
The following commit(s) were added to refs/heads/master by this push:
new bf5dfaface8 [fix](ci) harden the OSS upload: retry once, serialize
cron deploys, use the acceleration endpoint (#4165)
bf5dfaface8 is described below
commit bf5dfaface89d8d7b48bc8c054fb5a3974515bce
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Tue Sep 22 00:17:57 2026 +0800
[fix](ci) harden the OSS upload: retry once, serialize cron deploys, use
the acceleration endpoint (#4165)
## What
The 2026-09-21 12:05 cron deploy ([run
35597560821](https://github.com/apache/doris-website/actions/runs/35597560821/job/106325798481))
spent **2h04m** in "Upload files to OSS" and then failed, so the
asf-site deploy was skipped and the site stayed on the 08:43 build.
From the step log:
- The runner → OSS link was ~50x slower than usual for the whole two
hours: ~2 successful PUTs/s (the 08:06 run did ~110/s), and the final ~9
MB `.actioninfo` PUT alone took 16 minutes (6 s normally). #4163 had
changed the global CSS, so every HTML page (12,320 objects) had to be
re-sent. The slow segment was the GitHub runner (US) reaching the
bucket's regional endpoint over the public internet at Beijing evening
peak.
- **6 of the 12,320 PUTs** hit the SDK's 60 s timeouts (`net/http:
timeout awaiting response headers` ×4, `write tcp … i/o timeout` ×2).
The action exits 1 on any failed upload and has no retry (the OSS SDK it
embeds never reads its `RetryTimes`), so a 0.05% failure rate failed the
step - after 99.95% of the upload had gone through and been recorded in
the bucket's `.actioninfo` manifest.
## How
1. **Retry the upload step once** (`cron-deploy-website.yml`,
`manual-deploy-website.yml`). The first attempt gets `continue-on-error:
true`; a second identical step runs only when `steps.oss-upload.outcome
== 'failure'`, and a failure there still fails the job. The action
writes `.actioninfo` before exiting non-zero, so the retry only re-sends
the objects that failed plus the manifest. In this incident that would
have been 6 objects, and the job would have gone on to deploy asf-site
at ~15:25 instead of stopping.
2. **Concurrency group for the cron workflow** (`cron-deploy-website`,
`cancel-in-progress: false`). A slow run and the next 2-hourly trigger
otherwise push the same objects through the same pipe and race for the
manifest. The newer run queues instead; only the latest pending run is
kept, which is what a deploy-master cron wants. The manual workflow
deliberately gets no group: sharing one with the cron would let a cron
trigger evict a human's pending manual run, and separate manual runs are
rare and supervised.
3. **Upload through the transfer-acceleration endpoint** (all four
workflows that upload to the bucket). Transfer acceleration was enabled
on the website bucket on 2026-09-21, so the upload steps now use
`oss-accelerate.aliyuncs.com`: the runner enters Alibaba's backbone at
the nearest PoP instead of crossing the public internet to the bucket's
region. The endpoint is a public hostname, not a credential, so it is
written into the workflows rather than the `ALIYUN_OSS_ENDPOINT` secret
(changing that needs an INFRA ticket); the secret is now unreferenced
and can be deleted whenever convenient. The action prefixes the bucket
itself (`http://<bucket>.<endpoint>/…`), so the value stays a bare
hostname. Downloads are untouched: `cdnd.selectdb.com` keeps its
regional OSS origin, which already reaches the bucket over Alibaba's
network - pointing the CDN at the acceleration endpoint would only add a
hop and a second traffic bill.
Not done on purpose:
- **No `timeout-minutes` on the upload step.** The action writes its
manifest only at the very end, so killing a slow upload discards the
record of everything sent so far and the next run starts the whole
upload again. A 30-minute cap would have left the site undeployable for
as long as the slow period lasted, whereas the uncapped run plus one
retry would have deployed. A genuine hang is not possible either: every
request is bounded by the SDK's 30 s connect / 60 s read-write / 60 s
header timeouts. The job keeps GitHub's default 6 h ceiling.
## Follow-up outside this PR
- `cron-generate-pdf.yml` / `manual-generate-pdf.yml` upload `build-pdf`
with the action's default `incremental: true`, which would overwrite the
shared root `.actioninfo` with a manifest containing only the PDFs and
force the next website deploy to re-send all ~63k objects. It is latent
today because "Generate PDF" has failed on every recent run, but worth
`incremental: false` before anyone fixes the generator.
## Verified
All four files parse (js-yaml); the retry steps' `with:` blocks are
byte-identical to the first attempts'; `if:` uses `outcome` (not
`conclusion`, which `continue-on-error` reports as success). The SDK's
`urlMaker.Init` turns a bare hostname into
`http://<bucket>.<hostname>/`, so the endpoint value needs no scheme. An
anonymous request to `<bucket>.oss-accelerate.aliyuncs.com` is answered
by OSS (403 AccessDenied, as on the regional endpoint), i.e. the name
resolves and routes; whether acceleration is enabled on the bucket is
only visible in the console, where it was confirmed. Not exercisable
before merge: the workflows run on `schedule` / `workflow_dispatch` from
master - the first cron run after merge is the real test, and reverting
the endpoint commit alone restores the regional path.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01MvJw7xdszLCGBQdrvi7N9Z
---------
Co-authored-by: morningman <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
.github/workflows/cron-deploy-website.yml | 40 +++++++++++++++++++++++++++--
.github/workflows/cron-generate-pdf.yml | 4 +--
.github/workflows/manual-deploy-website.yml | 27 +++++++++++++++++--
.github/workflows/manual-generate-pdf.yml | 4 +--
4 files changed, 67 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/cron-deploy-website.yml
b/.github/workflows/cron-deploy-website.yml
index 3ba9185ee0b..6007b7495df 100644
--- a/.github/workflows/cron-deploy-website.yml
+++ b/.github/workflows/cron-deploy-website.yml
@@ -4,6 +4,15 @@ on:
schedule:
- cron: '0 */2 * * *' # Runs every 2 hours.
permissions: write-all
+# One deploy at a time. A run whose OSS upload crawls (the 2026-09-21 12:05
+# run spent two hours on it) must not overlap the next cron trigger: both
+# would push the same objects through the same slow pipe and race for the
+# bucket's .actioninfo manifest. Queue the newer run instead of cancelling
+# the running one - killing it mid-upload discards the manifest it writes at
+# the end, and the next run starts the whole upload over.
+concurrency:
+ group: cron-deploy-website
+ cancel-in-progress: false
jobs:
build-and-deploy:
runs-on: ubuntu-latest
@@ -85,13 +94,40 @@ jobs:
# ls ./build/assets/files/
- name: Upload files to OSS
+ id: oss-upload
+ # The action has no per-request retry (the OSS SDK it embeds
never
+ # reads its RetryTimes), so a single PUT hitting the SDK's 60s
+ # timeout among tens of thousands fails the whole step - on
+ # 2026-09-21 that was 6 of 12,320 uploads after two hours on a
slow
+ # link. It does write its .actioninfo manifest before exiting
+ # non-zero, so the retry below only re-sends the objects that
+ # failed, plus the manifest. continue-on-error keeps the job
alive
+ # for that retry; the retry step fails the job if it fails too.
+ continue-on-error: true
uses: ./.github/actions/aliyun-oss-website-action
with:
accessKeyId: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
accessKeySecret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
bucket: ${{ secrets.ALIYUN_OSS_BUCKET }}
- # use your own endpoint
- endpoint: ${{ secrets.ALIYUN_OSS_ENDPOINT }}
+ # Transfer-acceleration endpoint of the website bucket
(enabled
+ # on the bucket on 2026-09-21): the runner enters Alibaba's
+ # backbone at the nearest PoP instead of crossing the public
+ # internet to the bucket's region. Uploads only - the CDN
keeps
+ # its regional origin for downloads.
+ endpoint: oss-accelerate.aliyuncs.com
+ folder: build
+ onlyUpload: true
+ otherCacheControl: 0
+ skipSetting: true
+
+ - name: Upload files to OSS (retry)
+ if: steps.oss-upload.outcome == 'failure'
+ uses: ./.github/actions/aliyun-oss-website-action
+ with:
+ accessKeyId: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
+ accessKeySecret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
+ bucket: ${{ secrets.ALIYUN_OSS_BUCKET }}
+ endpoint: oss-accelerate.aliyuncs.com
folder: build
onlyUpload: true
otherCacheControl: 0
diff --git a/.github/workflows/cron-generate-pdf.yml
b/.github/workflows/cron-generate-pdf.yml
index 7d834303f07..87f85273c49 100644
--- a/.github/workflows/cron-generate-pdf.yml
+++ b/.github/workflows/cron-generate-pdf.yml
@@ -34,7 +34,7 @@ jobs:
accessKeyId: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
accessKeySecret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
bucket: ${{ secrets.ALIYUN_OSS_BUCKET }}
- # use your own endpoint
- endpoint: ${{ secrets.ALIYUN_OSS_ENDPOINT }}
+ # Transfer-acceleration endpoint, same as the website deploys.
+ endpoint: oss-accelerate.aliyuncs.com
folder: build-pdf
onlyUpload: true
diff --git a/.github/workflows/manual-deploy-website.yml
b/.github/workflows/manual-deploy-website.yml
index ff2351cf33f..0bc5d14e748 100644
--- a/.github/workflows/manual-deploy-website.yml
+++ b/.github/workflows/manual-deploy-website.yml
@@ -63,13 +63,36 @@ jobs:
export DORIS_COMMIT=`git rev-parse HEAD`
- name: Upload files to OSS
+ id: oss-upload
+ # Same retry as cron-deploy-website.yml: the action has no
+ # per-request retry, one timed-out PUT fails the step, and the
+ # .actioninfo manifest it writes before exiting lets a second run
+ # re-send only what failed.
+ continue-on-error: true
uses: ./.github/actions/aliyun-oss-website-action
with:
accessKeyId: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
accessKeySecret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
bucket: ${{ secrets.ALIYUN_OSS_BUCKET }}
- # use your own endpoint
- endpoint: ${{ secrets.ALIYUN_OSS_ENDPOINT }}
+ # Transfer-acceleration endpoint of the website bucket
(enabled
+ # on the bucket on 2026-09-21): the runner enters Alibaba's
+ # backbone at the nearest PoP instead of crossing the public
+ # internet to the bucket's region. Uploads only - the CDN
keeps
+ # its regional origin for downloads.
+ endpoint: oss-accelerate.aliyuncs.com
+ folder: build
+ onlyUpload: true
+ otherCacheControl: 0
+ skipSetting: true
+
+ - name: Upload files to OSS (retry)
+ if: steps.oss-upload.outcome == 'failure'
+ uses: ./.github/actions/aliyun-oss-website-action
+ with:
+ accessKeyId: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
+ accessKeySecret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
+ bucket: ${{ secrets.ALIYUN_OSS_BUCKET }}
+ endpoint: oss-accelerate.aliyuncs.com
folder: build
onlyUpload: true
otherCacheControl: 0
diff --git a/.github/workflows/manual-generate-pdf.yml
b/.github/workflows/manual-generate-pdf.yml
index 5bf1858d364..a0f12caa338 100644
--- a/.github/workflows/manual-generate-pdf.yml
+++ b/.github/workflows/manual-generate-pdf.yml
@@ -42,7 +42,7 @@ jobs:
accessKeyId: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
accessKeySecret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
bucket: ${{ secrets.ALIYUN_OSS_BUCKET }}
- # use your own endpoint
- endpoint: ${{ secrets.ALIYUN_OSS_ENDPOINT }}
+ # Transfer-acceleration endpoint, same as the website deploys.
+ endpoint: oss-accelerate.aliyuncs.com
folder: build-pdf
onlyUpload: true
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]