From dfc14113e3d0fc976e3cdeac8dbeac65f5394a51 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 28 May 2026 10:42:23 +0100 Subject: [PATCH 1/3] Change waitForProcessing to use exponential backoff --- lib/entry-points.js | 28 +++++++++++++++------------- src/upload-lib.ts | 44 +++++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 78a5f058af..3ee58bebb7 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -157473,22 +157473,18 @@ function dumpSarifFile(sarifPayload, outputDir, logger, uploadTarget) { logger.info(`Writing processed SARIF file to ${outputFile}`); fs21.writeFileSync(outputFile, sarifPayload); } -var STATUS_CHECK_FREQUENCY_MILLISECONDS = 5 * 1e3; -var STATUS_CHECK_TIMEOUT_MILLISECONDS = 2 * 60 * 1e3; +var STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS = 5 * 1e3; +var STATUS_CHECK_BACKOFF_MULTIPLIER = 2; +var STATUS_CHECK_MAX_TRIES = 5; async function waitForProcessing(repositoryNwo, sarifID, logger, options = { isUnsuccessfulExecution: false }) { logger.startGroup("Waiting for processing to finish"); try { const client = getApiClient(); - const statusCheckingStarted = Date.now(); - while (true) { - if (Date.now() > statusCheckingStarted + STATUS_CHECK_TIMEOUT_MILLISECONDS) { - logger.warning( - "Timed out waiting for analysis to finish processing. Continuing." - ); - break; - } + let statusCheckBackoff = STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS; + await delay(statusCheckBackoff, { allowProcessExit: false }); + for (let statusCheckCount = 1; statusCheckCount <= STATUS_CHECK_MAX_TRIES; statusCheckCount++) { let response = void 0; try { response = await client.request( @@ -157526,9 +157522,15 @@ ${response.data.errors}`; } else { assertNever(status); } - await delay(STATUS_CHECK_FREQUENCY_MILLISECONDS, { - allowProcessExit: false - }); + if (statusCheckCount === STATUS_CHECK_MAX_TRIES) { + logger.warning( + "Timed out waiting for analysis to finish processing. Continuing." + ); + break; + } else { + statusCheckBackoff *= STATUS_CHECK_BACKOFF_MULTIPLIER; + await delay(statusCheckBackoff, { allowProcessExit: false }); + } } } finally { logger.endGroup(); diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 83331aeed9..005227ea78 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -829,8 +829,10 @@ function dumpSarifFile( fs.writeFileSync(outputFile, sarifPayload); } -const STATUS_CHECK_FREQUENCY_MILLISECONDS = 5 * 1000; -const STATUS_CHECK_TIMEOUT_MILLISECONDS = 2 * 60 * 1000; +// Should lead to status checks after 5s, 15s, 35s, 75s, and 155s. +const STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS = 5 * 1000; +const STATUS_CHECK_BACKOFF_MULTIPLIER = 2; +const STATUS_CHECK_MAX_TRIES = 5; type ProcessingStatus = "pending" | "complete" | "failed"; @@ -854,20 +856,15 @@ export async function waitForProcessing( try { const client = api.getApiClient(); - const statusCheckingStarted = Date.now(); - while (true) { - if ( - Date.now() > - statusCheckingStarted + STATUS_CHECK_TIMEOUT_MILLISECONDS - ) { - // If the analysis hasn't finished processing in the allotted time, we continue anyway rather than failing. - // It's possible the analysis will eventually finish processing, but it's not worth spending more - // Actions time waiting. - logger.warning( - "Timed out waiting for analysis to finish processing. Continuing.", - ); - break; - } + // Do an initial wait because processing will always take a minimum of 2-3 seconds + let statusCheckBackoff = STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS; + await util.delay(statusCheckBackoff, { allowProcessExit: false }); + + for ( + let statusCheckCount = 1; + statusCheckCount <= STATUS_CHECK_MAX_TRIES; + statusCheckCount++ + ) { let response: OctokitResponse | undefined = undefined; try { response = await client.request( @@ -912,9 +909,18 @@ export async function waitForProcessing( util.assertNever(status); } - await util.delay(STATUS_CHECK_FREQUENCY_MILLISECONDS, { - allowProcessExit: false, - }); + if (statusCheckCount === STATUS_CHECK_MAX_TRIES) { + // If the analysis hasn't finished processing in the allotted time, we continue anyway rather than failing. + // It's possible the analysis will eventually finish processing, but it's not worth spending more + // Actions time waiting. + logger.warning( + "Timed out waiting for analysis to finish processing. Continuing.", + ); + break; + } else { + statusCheckBackoff *= STATUS_CHECK_BACKOFF_MULTIPLIER; + await util.delay(statusCheckBackoff, { allowProcessExit: false }); + } } } finally { logger.endGroup(); From d40e417f3c43e66dec164393f3b2b94722865c6f Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 1 Jun 2026 16:43:42 +0100 Subject: [PATCH 2/3] Only do initial wait when not running tests --- lib/entry-points.js | 4 +++- src/upload-lib.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 3ee58bebb7..1a19e2a491 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -157483,7 +157483,9 @@ async function waitForProcessing(repositoryNwo, sarifID, logger, options = { try { const client = getApiClient(); let statusCheckBackoff = STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS; - await delay(statusCheckBackoff, { allowProcessExit: false }); + if (process.env["NODE_ENV"] !== "test") { + await delay(statusCheckBackoff, { allowProcessExit: false }); + } for (let statusCheckCount = 1; statusCheckCount <= STATUS_CHECK_MAX_TRIES; statusCheckCount++) { let response = void 0; try { diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 005227ea78..83d1eaffb0 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -858,7 +858,9 @@ export async function waitForProcessing( // Do an initial wait because processing will always take a minimum of 2-3 seconds let statusCheckBackoff = STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS; - await util.delay(statusCheckBackoff, { allowProcessExit: false }); + if (process.env["NODE_ENV"] !== "test") { + await util.delay(statusCheckBackoff, { allowProcessExit: false }); + } for ( let statusCheckCount = 1; From b37e12b41831aa41d08ac6f6bcf633bd64de32b0 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 2 Jun 2026 10:01:35 +0100 Subject: [PATCH 3/3] Use isInTestMode() instead of NODE_ENV --- lib/entry-points.js | 2 +- src/upload-lib.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 1a19e2a491..9a6746c4d0 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -157483,7 +157483,7 @@ async function waitForProcessing(repositoryNwo, sarifID, logger, options = { try { const client = getApiClient(); let statusCheckBackoff = STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS; - if (process.env["NODE_ENV"] !== "test") { + if (!isInTestMode()) { await delay(statusCheckBackoff, { allowProcessExit: false }); } for (let statusCheckCount = 1; statusCheckCount <= STATUS_CHECK_MAX_TRIES; statusCheckCount++) { diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 83d1eaffb0..3895a53fa4 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -36,6 +36,7 @@ import { getRequiredEnvParam, GitHubVariant, GitHubVersion, + isInTestMode, satisfiesGHESVersion, } from "./util"; @@ -858,7 +859,7 @@ export async function waitForProcessing( // Do an initial wait because processing will always take a minimum of 2-3 seconds let statusCheckBackoff = STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS; - if (process.env["NODE_ENV"] !== "test") { + if (!isInTestMode()) { await util.delay(statusCheckBackoff, { allowProcessExit: false }); }