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); + }); });