From 044377e08739f81f63995ce00bc893dbe10f6269 Mon Sep 17 00:00:00 2001 From: Bilal Godil Date: Fri, 30 Jan 2026 15:05:17 -0800 Subject: [PATCH] fix tests --- .github/workflows/e2e-api-tests.yaml | 1 + .../workflows/e2e-custom-base-port-api-tests.yaml | 1 + .../workflows/e2e-source-of-truth-api-tests.yaml | 1 + ...estart-dev-and-test-with-custom-base-port.yaml | 1 + .github/workflows/restart-dev-and-test.yaml | 1 + .../setup-tests-with-custom-base-port.yaml | 1 + .github/workflows/setup-tests.yaml | 1 + .../internal/external-db-sync/poller/route.ts | 8 +++++--- .../internal/external-db-sync/sequencer/route.ts | 8 +++++--- .../endpoints/api/v1/external-db-sync-utils.ts | 15 +++++++++++++++ 10 files changed, 32 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e-api-tests.yaml b/.github/workflows/e2e-api-tests.yaml index fab629822..e819fe89e 100644 --- a/.github/workflows/e2e-api-tests.yaml +++ b/.github/workflows/e2e-api-tests.yaml @@ -20,6 +20,7 @@ jobs: STACK_ENABLE_HARDCODED_PASSKEY_CHALLENGE_FOR_TESTING: yes STACK_DATABASE_CONNECTION_STRING: "postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:8128/stackframe" STACK_FORCE_EXTERNAL_DB_SYNC: "true" + STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS: "5000" strategy: matrix: diff --git a/.github/workflows/e2e-custom-base-port-api-tests.yaml b/.github/workflows/e2e-custom-base-port-api-tests.yaml index e214d5907..dc12883f2 100644 --- a/.github/workflows/e2e-custom-base-port-api-tests.yaml +++ b/.github/workflows/e2e-custom-base-port-api-tests.yaml @@ -20,6 +20,7 @@ jobs: STACK_DATABASE_CONNECTION_STRING: "postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:6728/stackframe" NEXT_PUBLIC_STACK_PORT_PREFIX: "67" STACK_FORCE_EXTERNAL_DB_SYNC: "true" + STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS: "5000" strategy: matrix: diff --git a/.github/workflows/e2e-source-of-truth-api-tests.yaml b/.github/workflows/e2e-source-of-truth-api-tests.yaml index 4980c543f..aa3463192 100644 --- a/.github/workflows/e2e-source-of-truth-api-tests.yaml +++ b/.github/workflows/e2e-source-of-truth-api-tests.yaml @@ -22,6 +22,7 @@ jobs: STACK_TEST_SOURCE_OF_TRUTH: true STACK_DATABASE_CONNECTION_STRING: "postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:8128/stackframe" STACK_FORCE_EXTERNAL_DB_SYNC: "true" + STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS: "5000" strategy: matrix: diff --git a/.github/workflows/restart-dev-and-test-with-custom-base-port.yaml b/.github/workflows/restart-dev-and-test-with-custom-base-port.yaml index 2e4a64f17..4a1436db6 100644 --- a/.github/workflows/restart-dev-and-test-with-custom-base-port.yaml +++ b/.github/workflows/restart-dev-and-test-with-custom-base-port.yaml @@ -20,6 +20,7 @@ jobs: env: NEXT_PUBLIC_STACK_PORT_PREFIX: "69" STACK_FORCE_EXTERNAL_DB_SYNC: "true" + STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS: "5000" steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/restart-dev-and-test.yaml b/.github/workflows/restart-dev-and-test.yaml index 69e1edd97..d2769dde9 100644 --- a/.github/workflows/restart-dev-and-test.yaml +++ b/.github/workflows/restart-dev-and-test.yaml @@ -19,6 +19,7 @@ jobs: runs-on: ubicloud-standard-16 env: STACK_FORCE_EXTERNAL_DB_SYNC: "true" + STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS: "5000" steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/setup-tests-with-custom-base-port.yaml b/.github/workflows/setup-tests-with-custom-base-port.yaml index ea2a78243..aef1097bc 100644 --- a/.github/workflows/setup-tests-with-custom-base-port.yaml +++ b/.github/workflows/setup-tests-with-custom-base-port.yaml @@ -20,6 +20,7 @@ jobs: env: NEXT_PUBLIC_STACK_PORT_PREFIX: "69" STACK_FORCE_EXTERNAL_DB_SYNC: "true" + STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS: "5000" steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/setup-tests.yaml b/.github/workflows/setup-tests.yaml index 0611c9051..bfce50fd8 100644 --- a/.github/workflows/setup-tests.yaml +++ b/.github/workflows/setup-tests.yaml @@ -19,6 +19,7 @@ jobs: runs-on: ubicloud-standard-16 env: STACK_FORCE_EXTERNAL_DB_SYNC: "true" + STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS: "5000" steps: - uses: actions/checkout@v6 diff --git a/apps/backend/src/app/api/latest/internal/external-db-sync/poller/route.ts b/apps/backend/src/app/api/latest/internal/external-db-sync/poller/route.ts index dfcd36941..a249912a3 100644 --- a/apps/backend/src/app/api/latest/internal/external-db-sync/poller/route.ts +++ b/apps/backend/src/app/api/latest/internal/external-db-sync/poller/route.ts @@ -28,7 +28,9 @@ export const GET = createSmartRouteHandler({ headers: yupObject({ authorization: yupTuple([yupString()]).defined(), }).defined(), - query: yupObject({}).defined(), + query: yupObject({ + maxDurationMs: yupNumber().integer().min(1).optional(), + }).defined(), }), response: yupObject({ statusCode: yupNumber().oneOf([200]).defined(), @@ -38,14 +40,14 @@ export const GET = createSmartRouteHandler({ requests_processed: yupNumber().defined(), }).defined(), }), - handler: async ({ headers }) => { + handler: async ({ headers, query }) => { const authHeader = headers.authorization[0]; if (authHeader !== `Bearer ${getEnvVariable("CRON_SECRET")}`) { throw new StatusError(401, "Unauthorized"); } const startTime = performance.now(); - const maxDurationMs = 3 * 60 * 1000; + const maxDurationMs = query.maxDurationMs ?? 3 * 60 * 1000; const pollIntervalMs = 50; const staleClaimIntervalMinutes = 5; diff --git a/apps/backend/src/app/api/latest/internal/external-db-sync/sequencer/route.ts b/apps/backend/src/app/api/latest/internal/external-db-sync/sequencer/route.ts index f3a8c6551..3e8b1de26 100644 --- a/apps/backend/src/app/api/latest/internal/external-db-sync/sequencer/route.ts +++ b/apps/backend/src/app/api/latest/internal/external-db-sync/sequencer/route.ts @@ -246,7 +246,9 @@ export const GET = createSmartRouteHandler({ headers: yupObject({ authorization: yupTuple([yupString()]).defined(), }).defined(), - query: yupObject({}).defined(), + query: yupObject({ + maxDurationMs: yupNumber().integer().min(1).optional(), + }).defined(), }), response: yupObject({ statusCode: yupNumber().oneOf([200]).defined(), @@ -256,7 +258,7 @@ export const GET = createSmartRouteHandler({ iterations: yupNumber().defined(), }).defined(), }), - handler: async ({ headers }) => { + handler: async ({ headers, query }) => { const authHeader = headers.authorization[0]; if (authHeader !== `Bearer ${getEnvVariable("CRON_SECRET")}`) { throw new StatusError(401, "Unauthorized"); @@ -267,7 +269,7 @@ export const GET = createSmartRouteHandler({ const tenancyRefreshIntervalMs = 5_000; const startTime = performance.now(); - const maxDurationMs = 3 * 60 * 1000; + const maxDurationMs = query.maxDurationMs ?? 3 * 60 * 1000; const pollIntervalMs = 50; let iterations = 0; diff --git a/apps/e2e/tests/backend/endpoints/api/v1/external-db-sync-utils.ts b/apps/e2e/tests/backend/endpoints/api/v1/external-db-sync-utils.ts index c6bd6f20d..63ed21f94 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/external-db-sync-utils.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/external-db-sync-utils.ts @@ -11,6 +11,15 @@ export const POSTGRES_PASSWORD = process.env.EXTERNAL_DB_TEST_PASSWORD || 'PASSW export const TEST_TIMEOUT = 120000; export const HIGH_VOLUME_TIMEOUT = 600000; // 10 minutes for 1500+ users const SHOULD_FORCE_EXTERNAL_DB_SYNC = process.env.STACK_FORCE_EXTERNAL_DB_SYNC === 'true'; +const FORCE_SYNC_MAX_DURATION_MS = (() => { + const raw = process.env.STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS; + if (!raw) return 5000; + const parsed = Number.parseInt(raw, 10); + if (!Number.isFinite(parsed) || parsed <= 0) { + throw new Error('STACK_EXTERNAL_DB_SYNC_MAX_DURATION_MS must be a positive integer'); + } + return parsed; +})(); const FORCE_SYNC_INTERVAL_MS = 2000; let lastForcedSyncAt = -Infinity; @@ -165,11 +174,17 @@ async function maybeForceExternalDbSync() { } await niceFetch(new URL('/api/latest/internal/external-db-sync/sequencer', STACK_BACKEND_BASE_URL), { + query: { + maxDurationMs: String(FORCE_SYNC_MAX_DURATION_MS), + }, headers: { Authorization: `Bearer ${cronSecret}`, }, }); await niceFetch(new URL('/api/latest/internal/external-db-sync/poller', STACK_BACKEND_BASE_URL), { + query: { + maxDurationMs: String(FORCE_SYNC_MAX_DURATION_MS), + }, headers: { Authorization: `Bearer ${cronSecret}`, },