Skip to content

fix(admin): rethrow task-dispatched handler failures after logging - #129

Open
detail-app[bot] wants to merge 1 commit into
mainfrom
detail/bug-fix/fix-admin-rethrow-task-dispatched-handler-failures-5a59b5
Open

detail-app[bot] wants to merge 1 commit into
mainfrom
detail/bug-fix/fix-admin-rethrow-task-dispatched-handler-failures-5a59b5

Conversation

@detail-app

@detail-app detail-app Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Detail bug report: View on Detail

Bug

onTaskDispatchedEffect logged handler failures in its .catch and returned normally, so the underlying firebase-functions task-queue handler (onDispatchHandler) answered HTTP 204. Cloud Tasks treats any 2xx (incl. 204) as success and deletes the task, so retryConfig was inert on the handler-failure path — a transient failure (downstream 5xx, DB timeout, rate-limit) was permanently dequeued after one attempt. Introduced in 423946a; mirrors the swallow already fixed for onScheduleEffect in ee0385e.

Fix

Rethrow after logging in the wrapper's .catch (packages/admin/src/lib/functions/on-task-dispatched.ts), matching the onScheduleEffect precedent (ee0385e). The SDK now forwards a non-2xx status to Cloud Tasks: a plain Errorinternal500, an HttpsError → its mapped status. Cloud Tasks then retries per retryConfig (5xx is retry-class) or applies its 4xx policy. Effect.succeed remains the ack/no-retry signal.

Testing

  • Versioned unit tests (on-task-dispatched.spec.ts, 5 tests) drive the full SDK onDispatchHandler HTTP boundary via func(req, res): success → 204, plain Error failure → 500, HttpsError('unavailable')503, onSetupError ack of a malformed payload → 204, and a decode defect with no onSetupError500. Full admin suite passes (75 tests, 9 files).
  • Bug-fidelity cross-check (not versioned): temporarily reverted the one-line fix and re-ran the spec — the three failure-path tests fail with expected 204 to be 500/503 (the swallow), while the two success/recovery tests still pass; restore the fix, all pass — confirming the spec actually guards the rethrow.
  • Exhaustive validation (not versioned): during validation I also ran a 16-row it.each over the full HttpsError code→status map and 4 logger.error spy tests — all passed — but trimmed them from the final spec to keep it focused on the retry-contract footgun; a single unavailable → 503 case remains as the forwarding representative.
  • Routine checks: typecheck/build (nx run-many -t build), ESLint, and Prettier all clean; nx affected -t lint test build (CI parity) green.
  • Emulator end-to-end: stood up the firebase-tools Cloud Tasks + Functions emulators (installed a JDK, ran with a demo- project to skip production API auth, added a synthetic dist/package.json for runtime detection). With the fix, a fallible handler (Effect.fail, retryConfig.maxAttempts: 3) answered HTTP 500 and the Cloud Tasks emulator retried the task to maxAttempts exhaustion then marked it FAILED. With the fix reverted, the same handler answered HTTP 204 and the task was executed once then deleted with no retry (failedTasks: 0). This closes the 204 ⇒ delete / 5xx ⇒ retry chain that the unit tests stop one hop short of.

Closes #110


Automatic Fixes PRs can be configured here.

@detail-app
detail-app Bot requested a review from fwal as a code owner September 19, 2026 03:43
@github-actions github-actions Bot added 🐛 fix Something is broken or doesn't work properly 📦 admin labels Sep 19, 2026
@greptile-apps

greptile-apps Bot commented Sep 19, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

The PR appears safe to merge and correctly restores failure propagation without changing successful acknowledgement behavior.

Summary

This PR restores Cloud Tasks retry behavior by rethrowing task-handler failures after logging them.

  • Successful handlers and explicitly acknowledged setup errors continue to produce HTTP 204.
  • Plain handler failures now reach the Firebase Functions boundary and produce HTTP 500.
  • HttpsError responses preserve their mapped HTTP status.
  • New boundary-level tests cover successful acknowledgement, handler failures, mapped errors, and malformed payload behavior.
Diagram
sequenceDiagram
  participant CT as Cloud Tasks
  participant SDK as Firebase task handler
  participant Wrapper as onTaskDispatchedEffect
  participant Effect as Effect handler
  CT->>SDK: Dispatch task
  SDK->>Wrapper: Invoke callback
  Wrapper->>Effect: Decode and run task
  alt Effect succeeds or setup error is acknowledged
    Effect-->>Wrapper: Resolve
    Wrapper-->>SDK: Resolve
    SDK-->>CT: HTTP 204
  else Effect fails
    Effect-->>Wrapper: Reject
    Wrapper->>Wrapper: Log failure
    Wrapper-->>SDK: Rethrow failure
    SDK-->>CT: HTTP 500 or mapped HttpsError status
    CT->>CT: Apply retry policy
  end
Loading

Reviews (1) · Last reviewed commit: "fix(admin): rethrow task-dispatched hand..."

@fwal fwal added this to the 1.0 milestone Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📦 admin 🐛 fix Something is broken or doesn't work properly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Cloud Tasks: task handler failures are acknowledged as success, disabling retryConfig retries

1 participant