fix(GRO-2652): reset authInitPromise on failure so retry loop actually retries #225

Merged
Flea Flicker merged 2 commits from fix/GRO-2652-auth-promise-reset into dev 2026-08-05 10:00:13 +00:00
Member

Problem

QA identified a memoization bug in src/lib/auth.ts during review of PR #223 (dev→uat):

"Confirm that re-invoking initAuth() in the index.ts retry loop actually re-attempts initialization rather than re-awaiting an already-rejected memoized authInitPromise."

The bug: initAuth() stores the async IIFE in authInitPromise but never clears it on rejection. The index.ts startup retry loop calls initAuth() up to 10 times, but on attempt 2+:

if (authInitPromise) {
  await authInitPromise;  // immediately re-throws original rejection — no real retry
  return;
}

This means the 10-attempt retry loop in index.ts spins instantly, re-throwing the same rejected promise each time without ever hitting the DB again.

Fix

Wrap the final await authInitPromise in try/catch and reset authInitPromise = null on error:

try {
  await authInitPromise;
} catch (err) {
  authInitPromise = null; // allow retry on next call
  throw err;
}

Now each time initAuth() is called after a failure, the if (authInitPromise) guard is falsy and the function creates a fresh attempt (including a fresh DB query retry loop).

Acceptance Criteria Traceability

  • AC#2: process must NOT hard-crash on boot-time connection reset
    • This fix ensures the index.ts 10-attempt retry loop genuinely retries the DB connection on each call, not re-throws a stale rejection
    • Combined with the DB-level retry-with-backoff (5 attempts, 1s/2s/4s/8s) already in auth.ts, this gives the pod up to 10×5=50 DB connection attempts with exponential backoff before permanently degrading auth to 503

Related

  • Fixes bug identified during QA review of PR #223 (dev→uat for GRO-2652)
  • Parent fix PR: #222 (server-first startup + outer retry loop)
  • ci.yml + playbook PR: #224

Closes #GRO-2652 (partial — resolves retry memoization bug)
cc @cpfarhood

## Problem QA identified a memoization bug in `src/lib/auth.ts` during review of PR #223 (dev→uat): > "Confirm that re-invoking `initAuth()` in the `index.ts` retry loop actually re-attempts initialization rather than re-awaiting an already-rejected memoized `authInitPromise`." The bug: `initAuth()` stores the async IIFE in `authInitPromise` but never clears it on rejection. The `index.ts` startup retry loop calls `initAuth()` up to 10 times, but on attempt 2+: ```typescript if (authInitPromise) { await authInitPromise; // immediately re-throws original rejection — no real retry return; } ``` This means the 10-attempt retry loop in `index.ts` spins instantly, re-throwing the same rejected promise each time without ever hitting the DB again. ## Fix Wrap the final `await authInitPromise` in try/catch and reset `authInitPromise = null` on error: ```typescript try { await authInitPromise; } catch (err) { authInitPromise = null; // allow retry on next call throw err; } ``` Now each time `initAuth()` is called after a failure, the `if (authInitPromise)` guard is falsy and the function creates a fresh attempt (including a fresh DB query retry loop). ## Acceptance Criteria Traceability - AC#2: process must NOT hard-crash on boot-time connection reset - This fix ensures the index.ts 10-attempt retry loop genuinely retries the DB connection on each call, not re-throws a stale rejection - Combined with the DB-level retry-with-backoff (5 attempts, 1s/2s/4s/8s) already in auth.ts, this gives the pod up to 10×5=50 DB connection attempts with exponential backoff before permanently degrading auth to 503 ## Related - Fixes bug identified during QA review of PR #223 (dev→uat for GRO-2652) - Parent fix PR: #222 (server-first startup + outer retry loop) - ci.yml + playbook PR: #224 --- Closes #GRO-2652 (partial — resolves retry memoization bug) cc @cpfarhood
Flea Flicker added 1 commit 2026-08-05 09:46:40 +00:00
fix(GRO-2652): reset authInitPromise on failure so retry loop actually retries
CI / Lint & Typecheck (pull_request) Failing after 10s
CI / Test (pull_request) Failing after 24s
CI / Build & Push Docker Images (pull_request) Has been skipped
ae0ce3824f
Previously the initAuth() function set authInitPromise to the async IIFE's
Promise but never cleared it on rejection. The index.ts retry loop called
initAuth() up to 10 times, but on attempt 2+ the check
`if (authInitPromise) { await authInitPromise; return; }` would immediately
re-throw the original rejection without performing a real retry.

Fix: wrap the final `await authInitPromise` in try/catch and reset
authInitPromise = null on error. This allows the index.ts retry loop to
create a fresh attempt on each call after a failure.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Flea Flicker added 1 commit 2026-08-05 09:52:34 +00:00
fix(GRO-2652): reset authInitPromise on failure so retry loop actually retries
CI / Lint & Typecheck (pull_request) Successful in 19s
CI / Test (pull_request) Successful in 21s
CI / Build & Push Docker Images (pull_request) Successful in 53s
a1b27b5501
Previously the initAuth() function set authInitPromise to the async IIFE's
Promise but never cleared it on rejection. The index.ts retry loop called
initAuth() up to 10 times, but on attempt 2+ the check
`if (authInitPromise) { await authInitPromise; return; }` would immediately
re-throw the original rejection without performing a real retry.

Fix: wrap the final `await authInitPromise` in try/catch and reset
authInitPromise = null on error. This allows the index.ts retry loop to
create a fresh attempt on each call after a failure.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Flea Flicker merged commit f32e9a6889 into dev 2026-08-05 10:00:13 +00:00
Sign in to join this conversation.