diff --git a/__test__/warpbuild-mirror.test.ts b/__test__/warpbuild-mirror.test.ts index 1f75b013..8525a448 100644 --- a/__test__/warpbuild-mirror.test.ts +++ b/__test__/warpbuild-mirror.test.ts @@ -172,6 +172,11 @@ describe('warpbuild snapshot cache', () => { expect((await lookupSnapshot('123', SHA)).kind).toBe('miss') }) + it('maps 409 upload responses to locked (another job is uploading)', async () => { + stubFetch(409, {sub_code: 'FVE_GITMIRROR_LOCKED'}) + expect((await requestUploadURL('123', SHA)).kind).toBe('locked') + }) + it('maps 403 to disabled (backend kill switch)', async () => { stubFetch(403, {sub_code: 'PDE_GITMIRROR_DISABLED'}) expect((await lookupSnapshot('123', SHA)).kind).toBe('disabled') diff --git a/dist/index.js b/dist/index.js index 1cfe740e..241550eb 100644 --- a/dist/index.js +++ b/dist/index.js @@ -41699,7 +41699,8 @@ const promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.ur // Client for backend-core's /api/v1/git-mirrors endpoints, authed by the runner // verification token. Contract: 200 = presigned URL; 404 = miss (upload after the -// stock fetch); 403 = unservable org (skip cache + upload); else = fall back. +// stock fetch); 403 = unservable org (skip cache + upload); 409 = another job is +// uploading this snapshot (skip upload); else = fall back. const API_TIMEOUT_MS = 10_000; function backend_api_baseUrl() { return (process.env['WARPBUILD_HOST_URL'] || '').replace(/\/+$/, ''); @@ -41753,6 +41754,10 @@ async function requestUploadURL(repoKey, sha) { core_debug(`[wb-cache] upload-url answered 403 (disabled)`); return { kind: 'disabled' }; } + if (res.status === 409) { + core_debug(`[wb-cache] upload-url answered 409 (locked)`); + return { kind: 'locked' }; + } core_debug(`[wb-cache] upload-url answered ${res.status}`); return { kind: 'error' }; } @@ -41974,9 +41979,11 @@ async function uploadSnapshot(settings) { const size = (await external_fs_namespaceObject.promises.stat(tmpTar)).size; const upload = await requestUploadURL(repoKey, sha); if (upload.kind !== 'ok') { - info(upload.kind === 'disabled' - ? 'Snapshot cache is disabled by the backend; not uploading' - : 'Snapshot cache backend unavailable; not uploading'); + info(upload.kind === 'locked' + ? 'Another job is already uploading this snapshot; skipping' + : upload.kind === 'disabled' + ? 'Snapshot cache is disabled by the backend; not uploading' + : 'Snapshot cache backend unavailable; not uploading'); return; } const init = { diff --git a/src/warpbuild/backend-api.ts b/src/warpbuild/backend-api.ts index d51cd064..5f6ca858 100644 --- a/src/warpbuild/backend-api.ts +++ b/src/warpbuild/backend-api.ts @@ -3,7 +3,8 @@ import * as core from '@actions/core' // Client for backend-core's /api/v1/git-mirrors endpoints, authed by the runner // verification token. Contract: 200 = presigned URL; 404 = miss (upload after the -// stock fetch); 403 = unservable org (skip cache + upload); else = fall back. +// stock fetch); 403 = unservable org (skip cache + upload); 409 = another job is +// uploading this snapshot (skip upload); else = fall back. const API_TIMEOUT_MS = 10_000 @@ -22,6 +23,7 @@ export type SnapshotLookup = export type UploadURLResult = | {kind: 'ok'; url: string} | {kind: 'disabled'} + | {kind: 'locked'} | {kind: 'error'} function baseUrl(): string { @@ -89,6 +91,10 @@ export async function requestUploadURL( core.debug(`[wb-cache] upload-url answered 403 (disabled)`) return {kind: 'disabled'} } + if (res.status === 409) { + core.debug(`[wb-cache] upload-url answered 409 (locked)`) + return {kind: 'locked'} + } core.debug(`[wb-cache] upload-url answered ${res.status}`) return {kind: 'error'} } catch (error) { diff --git a/src/warpbuild/mirror-cache.ts b/src/warpbuild/mirror-cache.ts index 9e604e1b..0bfd32c9 100644 --- a/src/warpbuild/mirror-cache.ts +++ b/src/warpbuild/mirror-cache.ts @@ -253,9 +253,11 @@ async function uploadSnapshot(settings: IGitSourceSettings): Promise { const upload = await api.requestUploadURL(repoKey, sha) if (upload.kind !== 'ok') { core.info( - upload.kind === 'disabled' - ? 'Snapshot cache is disabled by the backend; not uploading' - : 'Snapshot cache backend unavailable; not uploading' + upload.kind === 'locked' + ? 'Another job is already uploading this snapshot; skipping' + : upload.kind === 'disabled' + ? 'Snapshot cache is disabled by the backend; not uploading' + : 'Snapshot cache backend unavailable; not uploading' ) return }