mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
fix(release): extend standalone runtime download retries (#15673)
* fix(release): extend standalone runtime download retries (#15672) Co-authored-by: Qwen-Coder <[email protected]> * docs(release): state retry-budget evidence without claiming the failing leg (#15672) The v0.26.2-preview.0 archive step aborted and passed on an unchanged re-run, but its job log was never retrievable, so raising the download retry budget from three to five attempts is defence-in-depth, not a confirmed fix for the download leg. Record that in the source comment and drop the same unconfirmed attribution from the retry test. * fix(release): correct retry-budget comment with attempt-1 log evidence The comment claimed the v0.26.2-preview.0 archive-step log was not retrievable and the failing leg unpinned. The job log is available via the Actions API and shows three consecutive 504s from the GitHub Releases CDN downloading the bun darwin-x64 runtime, so state the pinned leg directly. --------- Co-authored-by: Qwen Autofix <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: 易良 <[email protected]>
This commit is contained in:
2 files changed
+46
-6
No files matched your search
@@ -67,8 +67,12 @@ const DEFAULT_BUN_VERSION = '1.4.4';
|
||||
const BUN_RELEASE_BASE_URL = 'https://github.com/oven-sh/bun/releases/download';
|
||||
// The runtime downloads are the publish job's least reliable leg: one
|
||||
// transient download failure aborted the v0.23.4 publish while the
|
||||
// unchanged re-run passed. Bound each attempt and retry before failing.
|
||||
const MAX_DOWNLOAD_ATTEMPTS = 3;
|
||||
// unchanged re-run passed. The v0.26.2-preview.0 archive step aborted the
|
||||
// same way: its job log shows three consecutive 504s from the GitHub
|
||||
// Releases CDN while downloading the bun darwin-x64 runtime, and the
|
||||
// unchanged re-run passed. Five attempts back off to ~75s to ride out
|
||||
// longer transient bursts.
|
||||
const MAX_DOWNLOAD_ATTEMPTS = 5;
|
||||
const INITIAL_DOWNLOAD_BACKOFF_MS = 5_000;
|
||||
const DOWNLOAD_TIMEOUT_MS = 120_000;
|
||||
|
||||
|
||||
@@ -947,6 +947,40 @@ describe('standalone release packaging', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps retrying a transient download until a later attempt succeeds', async () => {
|
||||
const { downloadWithRetry } = await import(standaloneReleaseScriptUrl);
|
||||
const tmpDir = mkdtempSync(path.join(tmpdir(), 'qwen-download-retry-'));
|
||||
const destination = path.join(tmpDir, 'node-v22.0.0-linux-x64.tar.xz');
|
||||
const sleepImpl = vi.fn(async () => {});
|
||||
const fetchImpl = vi
|
||||
.fn()
|
||||
.mockRejectedValueOnce(new Error('fetch failed'))
|
||||
.mockRejectedValueOnce(new Error('fetch failed'))
|
||||
.mockRejectedValueOnce(new Error('fetch failed'))
|
||||
.mockRejectedValueOnce(new Error('fetch failed'))
|
||||
.mockResolvedValueOnce(new Response('runtime-bytes'));
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
|
||||
try {
|
||||
await downloadWithRetry(
|
||||
'https://nodejs.org/dist/v22.0.0/node-v22.0.0-linux-x64.tar.xz',
|
||||
destination,
|
||||
{ fetchImpl, sleepImpl },
|
||||
);
|
||||
|
||||
// A fourth transient failure must still leave one attempt, and a
|
||||
// success on the final attempt must still write the destination.
|
||||
expect(fetchImpl).toHaveBeenCalledTimes(5);
|
||||
expect(sleepImpl.mock.calls.map(([ms]) => ms)).toEqual([
|
||||
5_000, 10_000, 20_000, 40_000,
|
||||
]);
|
||||
expect(readFileSync(destination, 'utf8')).toBe('runtime-bytes');
|
||||
} finally {
|
||||
warnSpy.mockRestore();
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('re-downloads a runtime archive that fails verification', async () => {
|
||||
const { downloadWithRetry } = await import(standaloneReleaseScriptUrl);
|
||||
const tmpDir = mkdtempSync(path.join(tmpdir(), 'qwen-download-retry-'));
|
||||
@@ -992,8 +1026,10 @@ describe('standalone release packaging', () => {
|
||||
{ fetchImpl, sleepImpl },
|
||||
),
|
||||
).rejects.toThrow(/Failed to download/);
|
||||
expect(fetchImpl).toHaveBeenCalledTimes(3);
|
||||
expect(sleepImpl.mock.calls.map(([ms]) => ms)).toEqual([5_000, 10_000]);
|
||||
expect(fetchImpl).toHaveBeenCalledTimes(5);
|
||||
expect(sleepImpl.mock.calls.map(([ms]) => ms)).toEqual([
|
||||
5_000, 10_000, 20_000, 40_000,
|
||||
]);
|
||||
} finally {
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
@@ -1078,7 +1114,7 @@ describe('standalone release packaging', () => {
|
||||
).rejects.toThrow(
|
||||
`ERROR: ${label} SHASUMS256.txt does not list ${missingArchives.join(', ')}`,
|
||||
);
|
||||
expect(fetchImpl).toHaveBeenCalledTimes(3);
|
||||
expect(fetchImpl).toHaveBeenCalledTimes(5);
|
||||
} finally {
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
@@ -1175,7 +1211,7 @@ describe('standalone release packaging', () => {
|
||||
expect(normalised).toMatch(
|
||||
/downloadRuntimeChecksums\(\{[^;]*expectedArchives: RELEASE_TARGETS\.map/,
|
||||
);
|
||||
expect(normalised).toContain('const MAX_DOWNLOAD_ATTEMPTS = 3;');
|
||||
expect(normalised).toContain('const MAX_DOWNLOAD_ATTEMPTS = 5;');
|
||||
expect(normalised).toContain('const INITIAL_DOWNLOAD_BACKOFF_MS = 5_000;');
|
||||
expect(normalised).toContain('const DOWNLOAD_TIMEOUT_MS = 120_000;');
|
||||
expect(normalised).toContain('AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)');
|
||||
|
||||
Reference in new issue
Block a user