From ae534b3ada868ca3505b541b8ec7298b19793643 Mon Sep 17 00:00:00 2001 From: sunnylqm Date: Tue, 29 Sep 2026 17:29:34 +0800 Subject: [PATCH] fix(upload): allow 5 s per MB for the upload deadline 1 s/MB assumed ~1 MB/s sustained, which slower CI egress or a congested link does not reach, so large packages timed out mid-transfer. The deadline is now 30 s + 5 s/MB (about 200 KB/s), still at least 60 s and still absolute, e.g. 530 s for a 100 MB package. Co-Authored-By: Claude Opus 5.5 --- src/api.ts | 9 +++++---- tests/api.test.ts | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/api.ts b/src/api.ts index 6d7e7fe..74c8a34 100644 --- a/src/api.ts +++ b/src/api.ts @@ -246,11 +246,12 @@ export const post = queryWithBody('POST'); export const put = queryWithBody('PUT'); export const doDelete = queryWithBody('DELETE'); -// Upload deadline: generous for a slow link (1 s/MB on top of a 30 s base, -// never below 60 s) but bounded, so a stalled connection cannot hang a CI job -// forever. The bar keeps ticking while bytes flow; the deadline is absolute. +// Upload deadline: generous for a slow link (5 s/MB, i.e. ~200 KB/s, on top +// of a 30 s base, never below 60 s) but bounded, so a stalled connection cannot +// hang a CI job forever. The bar keeps ticking while bytes flow; the deadline +// is absolute. const UPLOAD_TIMEOUT_BASE_MS = 30_000; -const UPLOAD_TIMEOUT_PER_MB_MS = 1_000; +const UPLOAD_TIMEOUT_PER_MB_MS = 5_000; const UPLOAD_TIMEOUT_MIN_MS = 60_000; const UPLOAD_MAX_RETRIES = 1; diff --git a/tests/api.test.ts b/tests/api.test.ts index cd4185e..01e1761 100644 --- a/tests/api.test.ts +++ b/tests/api.test.ts @@ -19,6 +19,7 @@ import { replaceSession, saveSession, setApiToken, + uploadTimeoutMs, } from '../src/api'; import * as runtime from '../src/utils/runtime'; @@ -289,4 +290,13 @@ describe('api.ts error helpers', () => { }), ).toBe(true); }); + test('upload deadline allows 5 s per MB on a 30 s base, at least 60 s', () => { + const mb = 1048576; + expect(uploadTimeoutMs(0)).toBe(60_000); + expect(uploadTimeoutMs(5 * mb)).toBe(60_000); + expect(uploadTimeoutMs(10 * mb)).toBe(80_000); + expect(uploadTimeoutMs(100 * mb)).toBe(530_000); + // a partial megabyte counts as a whole one + expect(uploadTimeoutMs(100 * mb + 1)).toBe(535_000); + }); });