Commit Graph

4 Commits

Author SHA1 Message Date
MechaCat02
fb4182f68d fix(admin): clear session-expired flag on successful browser restart (0.53.1)
A successful `coordinated_restart` re-runs `on_launch`, which re-injects
PHPSESSID and re-probes via `verify_session_with_recircuit` — so reaching
`Ok(())` proves the session is live. But the handler never dropped the
sticky `session_expired` flag, so the admin UI continued to report
"Session Expired" and chapter workers kept idling until the operator
made a second click on "Clear expired" (or pushed a new cookie).

The fix is one line in `restart_browser`: on `Ok(())`, call
`c.session.clear_expired()`. The error path still leaves the flag set
since a failed restart means the probe didn't confirm.

Adds a focused `clear_expired_flips_sticky_flag_without_touching_session`
unit test to pin the controller-side semantic; the existing
`update_persists_and_clears_expired_then_round_trips` test continues to
cover the cookie-refresh path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-04 19:49:28 +02:00
MechaCat02
da6e320836 feat(crawler): live status via SSE instead of polling
Replace the dashboard's 5s polling with a Server-Sent Events stream:

- StatusHandle gains a tokio `watch` version bumped on every mutation;
  GET /admin/crawler/stream subscribes and pushes a composed snapshot
  immediately on connect, then on every status change (instant, no
  lost-wakeup) plus a 5s backstop for DB queue counts / browser phase.
- Non-status signals poke the notifier so they push immediately too:
  session-expired (worker), session update / clear-expired / browser
  restart (endpoints).
- compose_status is shared by the one-shot GET and the stream; the stream
  tolerates transient DB errors with a keep-alive comment instead of
  tearing down.

Frontend: the crawler page opens an EventSource on mount and closes it on
destroy, so the subscription is scoped to the active page (no global
subscription). A one-shot fetch still paints initial state / serves as a
fallback if SSE is blocked; a live/reconnecting indicator reflects the
connection. The existing reverse proxy already streams SSE (its abort
timer is cleared once response headers arrive), so no proxy change needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 19:13:50 +02:00
MechaCat02
6f0a8d88c9 feat(api): add per-chapter requeue scope for dead jobs
Lets the admin manga page requeue a single failed chapter's dead job(s)
inline, without a job id. Adds RequeueScope::Chapter + the matching
request variant and a repo test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:48:13 +02:00
MechaCat02
41bf9455a1 feat(api): admin crawler observability + control endpoints
GET  /admin/crawler                      live status (phase, workers,
                                          last pass, session, browser, queue)
POST /admin/crawler/run                  trigger an out-of-cycle metadata pass
POST /admin/crawler/browser/restart      coordinated Chromium restart
POST /admin/crawler/session              refresh PHPSESSID + re-probe
POST /admin/crawler/session/clear-expired clear the sticky expired flag
GET  /admin/crawler/dead-jobs            paginated dead-letter list
POST /admin/crawler/dead-jobs/requeue    requeue all / per-manga / single

All cookie-only via RequireAdmin; control endpoints 503 when the daemon is
disabled; mutations are audit-logged. Reads compose the live status with
DB-derived queue counts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:39:04 +02:00