Commit Graph

1 Commits

Author SHA1 Message Date
Víctor Falcón d3ec96b845
fix(onboarding): stop the AI rule-suggestion step from hanging forever (#705)
## Problem

A user reported being stuck forever on the onboarding "Looking for
patterns" step (the "Polishing your suggestions…" spinner). Confirmed in
prod: their `suggestion_runs` row has been stuck in `processing` for a
week, and `failed_jobs` shows `TimeoutExceededException:
GenerateRuleSuggestionsJob has timed out`.

### Root cause

- The user has 4,163 transactions — the largest onboarding dataset (max
with a completed run was 3,481). The Gemini generation exceeded the
job's `$timeout = 120`.
- The worker timeout is raised **outside** the `try/catch` in
`GenerateRuleSuggestions::run()`, so the code that sets `status =
Failed` never ran.
- `GenerateRuleSuggestionsJob` had **no `failed()` handler** (5 other
jobs do), so nothing flipped the run to `Failed`. It stayed
`processing`, `show()` kept returning `processing`, and the client
polled every 3s forever.
- The timeout never reached Sentry, so it was invisible. Only 1 user
affected, but it's a latent bug that recurs on any large account.

## Fix

**Backend** — add `failed()` to `GenerateRuleSuggestionsJob`: mark the
run `Failed` (only if not already terminal) and `report()` the exception
so these surface in Sentry.

**Frontend** (`step-ai-suggestions.tsx`) — belt-and-suspenders so the
client never spins forever even if the worker dies before it can mark
the run:
- `poll()` now guards against transient errors (network blip / expired
session / 5xx) instead of silently dying.
- A client-side deadline (3 min, just beyond the "up to two minutes"
copy) surfaces the existing "couldn't generate" screen with **Try again
/ Skip**.

Not included: raising the timeout / capping the number of groups sent to
Gemini so large accounts *complete* instead of just being able to skip.
Follow-up if we want big accounts to get suggestions.

## Tests

- `tests/Feature/Ai/GenerateRuleSuggestionsJobTest.php` — `failed()`
marks the run `Failed` + reports; doesn't overwrite an already-terminal
run.
-
`resources/js/components/onboarding/step-ai-suggestions-timeout.test.tsx`
— after the deadline the spinner gives way to the failed screen.

Green locally: pint, prettier, eslint, backend + frontend tests.
2026-07-20 18:10:51 +00:00