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
fix: strip the shipped payload and mirror assets concurrently (2026.7.29.1)
The GitCode mirror leg of `publish-ecosystem` has failed four releases in a
row — 0.0.94 / 0.0.97 / 0.0.105 / 2026.7.28.2 — each time on the biggest
tarballs, each time costing ~5 minutes of manual `gtc release upload`. The
per-asset 180s cap was tuned three times without anyone measuring what it was
capping. Probe PR #301 measured it:
GitHub US runner -> file.gitcode.com 0.012 MB/s <- the failing path
same runner <- file.gitcode.com 3.87 MB/s
same runner -> github.com 16 MB/s
mainland-CN host -> file.gitcode.com 1.84 MB/s
file.gitcode.com is a single Huawei Cloud origin in Beijing, so it is the
inbound-to-CN direction that is shaped — not the host (the same runner
downloads from it at 3.87 MB/s), not the client (curl and urllib measure
identically), and not the runner's egress (16 MB/s to GitHub). The rate also
swings ~4.6x run to run, so no fixed per-asset cap can be both safe and
useful. At 0.012 MB/s a 34.8MB asset needs ~45 minutes; 180s never had a
chance.
Two fixes, both measured rather than guessed.
S1 — stop shipping 30MB of debug info. Of the 34.8MB linux-x86_64 tarball,
almost none was mcpp: the vendored `registry/bin/xlings` shipped at 97.3MB
with full debug info (86.9MB on aarch64) against a 4.3MB mcpp. Stripping both
takes the tarball to 4.62MB — 7.5x — and the stripped binaries were verified
working (`--version`, `new`, `build`, `run`). Two defects made this possible:
* the vendored xlings was never stripped at any of the four injection sites,
only `cp`'d;
* the x86_64 `strip` that DID exist ran before `mcpp pack`, which rebuilds
the binary and overwrote it — which is why every release up to and
including 2026.7.28.2 shipped an unstripped bin/mcpp while aarch64 (which
stages by hand) shipped a stripped one.
tools/slim_linux_payload.sh now strips both binaries on the STAGED payload and
ASSERTS the result, so a strip that silently stops working fails the release
instead of quietly shipping a fat tarball again. The aarch64 leg's
best-effort `|| true` strip is now a hard requirement. macOS and Windows are
deliberately left alone: their payloads are already 6.1MB / 4.2MB, and
stripping a Mach-O invalidates its ad-hoc signature.
S2 — mirror a host's assets concurrently, and bound the LEG instead of each
asset. The shaping is per-connection: 1/4/8 concurrent 1MB uploads took
76s/80s/93s wall (6.6x aggregate at N=8). Assets within a leg now upload in
parallel under MIRROR_MAX_PARALLEL, and MIRROR_UPLOAD_TIMEOUT is replaced by
MIRROR_LEG_DEADLINE_GH/GTC. The v0.0.90 rule still holds — nothing is killed
and retried inside a round, because the presigned OBS PUT has no
multipart/resume (confirmed in #301); exhausting the budget ends the leg and
the completeness gate fails loudly as before.
Together the gitcode leg goes from ~45 min plus a manual step to ~6 min
unattended, and every user's download shrinks 7.5x.
Verified locally: slim on the real 2026.7.28.2 payload (101.6MB -> 13.9MB of
binaries, 34.81MB -> 4.62MB tarball, stripped mcpp builds and runs an
`import std` project); an isolated harness for the concurrent launcher
(bounded concurrency, ordered log replay, correct per-asset success/failure);
a full real mirror_res.sh run against the existing 2026.7.28.2 tag (all
skipped, gate 16/16); and a real parallel-upload run on a throwaway
`0.0.0-mirrortest` tag against BOTH hosts (gate 8/8, exit 0), whose artifacts
were deleted afterwards with the real release verified intact.
NB: release.yml is not exercised by PR CI — it runs on tag/dispatch only — so
S1 lands its first real proof at the next release, where the new assertions
fail loudly rather than silently.
info "WARN: $host$a ($sz) exceeded the ${MIRROR_UPLOAD_TIMEOUT}s cap after ${elapsed}s — skipping (not retried; the verify gate below decides the release)"
115
+
info "WARN: $host$a ($sz) hit the leg deadline after ${elapsed}s — abandoning (the verify gate below decides the release)"
91
116
return 1
92
117
fi
93
118
info "$host$a ($sz) uploaded in ${elapsed}s"
@@ -146,39 +171,73 @@ verify_batch() { # base_url asset... → prints assets still not serving
146
171
# - NEVER kill a slow-but-progressing upload AND RETRY IT. v0.0.90 wrapped
147
172
# uploads in `timeout 300`, so every cross-border PUT >5min was SIGKILLed
148
173
# at 60%% and restarted from byte zero — the 20min job ceiling fell to
149
-
# this. MIRROR_UPLOAD_TIMEOUT keeps a cap but ABANDONS the asset instead of
150
-
# retrying it, which is what makes the cap safe; the gate then fails the
151
-
# release loudly rather than thrashing until the job is killed.
174
+
# this. Nothing is killed-and-retried inside a round now: an upload gets
175
+
# the remaining LEG budget, and exhausting it ends the leg.
152
176
# - gtc's exit code lies both ways (obs_callback flakiness); the download
153
-
# probe is the only source of truth.
154
-
mirror_host() { # kind(gh|gtc) base_url
155
-
local kind="$1" base="$2" try a
177
+
# probe is the only source of truth. Measured mechanism (#301): the
178
+
# presigned PUT carries an `x-obs-callback` header pointing at
179
+
# api.gitcode.com; OBS stores the object and THEN calls back, so a failed
180
+
# callback reports `code:400 ... EOF` for an upload that did land.
181
+
#
182
+
# Assets within a leg upload CONCURRENTLY (the shaping is per-connection —
183
+
# see the deadline block at the top). Each upload runs in its own subshell
184
+
# writing to its own log, which is replayed in asset order after the wait, so
185
+
# concurrent progress lines don't interleave into unreadable soup.
echo"[mirror] hint: if the asset above was WARNed as capped at ${MIRROR_UPLOAD_TIMEOUT}s, either raise MIRROR_UPLOAD_TIMEOUT for this run or push it by hand:">&2
294
+
echo"[mirror] hint: if the asset above was WARNed at a leg deadline, raise MIRROR_LEG_DEADLINE_GH/GTC for this run, or push it by hand:">&2
0 commit comments