Downloads burst-prevention + maintenance-menu fix + gdl timeout #35

Merged
bvandeusen merged 0 commits from dev into main 2026-05-30 11:43:19 -04:00
bvandeusen commented 2026-05-30 11:40:51 -04:00 (Migrated from git.fabledsword.com)

Summary

  • 77e9859 Rewire the Subscriptions → Downloads MaintenanceMenu to the downloads pipeline. "Retry failed" now bulk-retries failing sources (same loop as the existing RETRY ALL — sourcesStore.checkNow per source); "Force recovery sweep" triggers recover_stalled_download_events on demand via a new POST /api/downloads/recover-stalled endpoint. The menu was wired to the filesystem-import retry endpoint and queued nothing visible from the Downloads view.
  • d28db32 Pin SourceConfig.timeout default to 900s (matches Celery download_source.soft_time_limit) instead of the inverted 3600s. gallery-dl now raises subprocess.TimeoutExpired inside Celery's kill window, so the existing clean-error branch (gallery_dl.py:635) actually fires — hangs flip to error_type='timeout' in ~15 min instead of ~40 min via SIGKILL + recovery sweep. Per-source config_overrides.timeout still bumps for legitimately long syncs.
  • 61ce1ce Platform-wide cooldown on ErrorType.RATE_LIMITED: _update_source_health stamps AppSetting("platform_cooldown:<platform>", expires_iso) with a 15-min cooldown. select_due_sources excludes every source whose platform is in active cooldown; scheduler_status surfaces them as platform_cooldowns: {platform: iso}. Burst-prevention for multi-worker setups (N due Patreon sources no longer all retry into the same rate limit at once). INSERT ... ON CONFLICT DO UPDATE so concurrent workers don't race into rolled-back transactions.
  • ff9e96e Updated two pinned key-set assertions (test_schedule_status_shape, test_summary_returns_rollup_shape) for the new platform_cooldowns field.

No alembic migrations. No new env vars. New backend surface: POST /api/downloads/recover-stalled (202 + {queued: true}).

Test plan

After :latest rebuilds and compose restarts:

  • Subscriptions → Downloads → Maintenance dropdown → Retry failed → toast N queued, M already running; rerun-buttons spin on source rows.
  • Same dropdown → Force recovery sweep → toast "Recovery sweep queued — refreshing in a few seconds"; failing rollup auto-refreshes after 4s.
  • Retry a failing source whose download still fails → flips to error in ~15 min with error_type: timeout (or rate_limited), not ~30–40 min with stranded by recovery sweep.
  • If multiple sources on the same platform are due and one hits a rate limit, subsequent ticks skip the rest of that platform for 15 min — visible at /api/system/activity/summary under scheduler.platform_cooldowns.

🤖 Generated with Claude Code

## Summary - **`77e9859`** Rewire the Subscriptions → Downloads MaintenanceMenu to the downloads pipeline. "Retry failed" now bulk-retries failing sources (same loop as the existing RETRY ALL — `sourcesStore.checkNow` per source); "Force recovery sweep" triggers `recover_stalled_download_events` on demand via a new `POST /api/downloads/recover-stalled` endpoint. The menu was wired to the filesystem-import retry endpoint and queued nothing visible from the Downloads view. - **`d28db32`** Pin `SourceConfig.timeout` default to **900s** (matches Celery `download_source.soft_time_limit`) instead of the inverted **3600s**. gallery-dl now raises `subprocess.TimeoutExpired` *inside* Celery's kill window, so the existing clean-error branch (`gallery_dl.py:635`) actually fires — hangs flip to `error_type='timeout'` in ~15 min instead of ~40 min via SIGKILL + recovery sweep. Per-source `config_overrides.timeout` still bumps for legitimately long syncs. - **`61ce1ce`** Platform-wide cooldown on `ErrorType.RATE_LIMITED`: `_update_source_health` stamps `AppSetting("platform_cooldown:<platform>", expires_iso)` with a 15-min cooldown. `select_due_sources` excludes every source whose platform is in active cooldown; `scheduler_status` surfaces them as `platform_cooldowns: {platform: iso}`. Burst-prevention for multi-worker setups (N due Patreon sources no longer all retry into the same rate limit at once). `INSERT ... ON CONFLICT DO UPDATE` so concurrent workers don't race into rolled-back transactions. - **`ff9e96e`** Updated two pinned key-set assertions (`test_schedule_status_shape`, `test_summary_returns_rollup_shape`) for the new `platform_cooldowns` field. No alembic migrations. No new env vars. New backend surface: `POST /api/downloads/recover-stalled` (202 + `{queued: true}`). ## Test plan After `:latest` rebuilds and compose restarts: - [ ] Subscriptions → Downloads → Maintenance dropdown → **Retry failed** → toast `N queued, M already running`; rerun-buttons spin on source rows. - [ ] Same dropdown → **Force recovery sweep** → toast "Recovery sweep queued — refreshing in a few seconds"; failing rollup auto-refreshes after 4s. - [ ] Retry a failing source whose download still fails → flips to `error` in **~15 min** with `error_type: timeout` (or `rate_limited`), not ~30–40 min with `stranded by recovery sweep`. - [ ] If multiple sources on the same platform are due and one hits a rate limit, subsequent ticks skip the rest of that platform for 15 min — visible at `/api/system/activity/summary` under `scheduler.platform_cooldowns`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/FabledCurator#35