Thanks to visit codestin.com
Credit goes to GitHub.com

Skip to content

fix(backups): add failure cooldown and export throttling#1214

Merged
s0up4200 merged 4 commits intodevelopfrom
codex/fix-qbittorrent-crash-during-backups
Feb 12, 2026
Merged

fix(backups): add failure cooldown and export throttling#1214
s0up4200 merged 4 commits intodevelopfrom
codex/fix-qbittorrent-crash-during-backups

Conversation

@s0up4200
Copy link
Collaborator

@s0up4200 s0up4200 commented Jan 11, 2026

Motivation

  • Prevent rapid retries and noisy scheduling after failed or canceled backup runs by introducing a cooldown window.
  • Avoid scheduling a missed backup while a previous run is still pending or running.
  • Reduce load on qBittorrent during backups by throttling repeated torrent export calls.

Description

  • Added FailureCooldown and ExportThrottle to the backup Config and set sensible defaults in NewService (10m and 200ms respectively).
  • Updated isBackupMissed to short-circuit when the latest run is pending or running, and to respect a failure cooldown for failed and canceled runs using CompletedAt or RequestedAt as the reference time.
  • Implemented export throttling in executeBackup by creating a time.Ticker based on ExportThrottle and selecting on its channel before each syncManager.ExportTorrent call, and ensured the ticker is stopped with defer.
  • Included BackupRunStatusCanceled in the cooldown logic and preserved existing logic that finds the most recent successful run as the schedule reference.

Testing

  • No automated tests were executed for these changes.

Codex Task

Summary by CodeRabbit

  • New Features

    • Added configurable FailureCooldown and ExportThrottle to control retry timing and export pacing
    • Exposed the configured data directory via a new public method
    • Added export-throttle gating and improved progress updates during export/import workflows
  • Bug Fixes

    • Prevents scheduling premature backups when a recent run is pending, running, or within the cooldown window
  • Tests

    • Added unit tests covering scheduling, cooldown, missed-backup cases, and export-throttle behavior

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 11, 2026

Walkthrough

Added configurable FailureCooldown and ExportThrottle; missed-backup detection now short-circuits for pending/running runs or recent cancellations; export operations are throttled via a ticker and waitForExportThrottle gating; Service.DataDir() accessor added; expanded per-run progress updates.

Changes

Cohort / File(s) Summary
Backup service core
internal/backups/service.go
Add FailureCooldown and ExportThrottle to Config with defaults; short-circuit missed-backup scheduling for pending/running or recent runs; add export throttling (ticker/channel) and waitForExportThrottle gating integrated into executeBackup; expose Service.DataDir().
Unit tests
internal/backups/service_test.go
Add tests for isBackupMissed behavior (pending/running runs, canceled within cooldown, failed outside cooldown) and for export throttling helper (no-op without throttle, tick wake, context cancellation) plus related edge cases.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Scheduler
    participant Service
    participant Throttle as ExportThrottleTicker
    participant Exporter
    participant Progress as ProgressTracker

    Scheduler->>Service: isBackupMissed()
    Service-->>Scheduler: return missed? (short-circuit if pending/running or within FailureCooldown)
    opt backup needed
      Service->>Progress: init run progress
      loop per torrent/blob
        Service->>Throttle: waitForExportThrottle(ctx)
        Throttle-->>Service: tick / allow
        Service->>Exporter: ExportTorrent(blob)
        Exporter-->>Service: result (ok/error)
        Service->>Progress: update per-torrent progress
      end
      Service->>Progress: finalize run
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

torrent

Poem

🐰
I hop through torrents, one gentle beat,
Pausing for cooldown, pacing my feet.
Throttle the exports, steady and bright,
Progress tracks sparkle in morning light,
A bunny's small cheer for backups done right. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding failure cooldown and export throttling to the backups service.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-qbittorrent-crash-during-backups

No actionable comments were generated in the recent review. 🎉


Comment @coderabbitai help to get the list of available commands and usage tips.

@s0up4200 s0up4200 changed the title Add backup failure cooldown and export throttling fix(backups): add failure cooldown and export throttling Jan 11, 2026
@s0up4200 s0up4200 linked an issue Jan 11, 2026 that may be closed by this pull request
2 tasks
@s0up4200 s0up4200 added this to the v1.14.0 milestone Jan 11, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @internal/backups/service.go:
- Around line 315-335: Remove the redundant nil check guarding the cooldown
comparison: after assigning ref := r.CompletedAt and falling back to ref =
&r.RequestedAt, ref is always non-nil, so replace the conditional "if ref != nil
&& now.Before(ref.Add(s.cfg.FailureCooldown))" with just "if
now.Before(ref.Add(s.cfg.FailureCooldown))" inside the loop that iterates over
runs (the block referencing r.CompletedAt, r.RequestedAt, s.cfg.FailureCooldown
and now.Before).
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 007d87e and c483ecb.

📒 Files selected for processing (1)
  • internal/backups/service.go
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: s0up4200
Repo: autobrr/qui PR: 632
File: internal/backups/service.go:1401-1404
Timestamp: 2025-11-25T22:46:03.762Z
Learning: In qui's backup service (internal/backups/service.go), background torrent downloads initiated during manifest import intentionally use a fire-and-forget pattern with the shared service context (s.ctx). Per-run cancellation is not needed, as orphaned downloads completing after run deletion are considered harmless and acceptable. This design prioritizes simplicity over per-run lifecycle management for background downloads.
📚 Learning: 2025-11-25T22:46:03.762Z
Learnt from: s0up4200
Repo: autobrr/qui PR: 632
File: internal/backups/service.go:1401-1404
Timestamp: 2025-11-25T22:46:03.762Z
Learning: In qui's backup service (internal/backups/service.go), background torrent downloads initiated during manifest import intentionally use a fire-and-forget pattern with the shared service context (s.ctx). Per-run cancellation is not needed, as orphaned downloads completing after run deletion are considered harmless and acceptable. This design prioritizes simplicity over per-run lifecycle management for background downloads.

Applied to files:

  • internal/backups/service.go
📚 Learning: 2025-12-28T18:44:10.496Z
Learnt from: s0up4200
Repo: autobrr/qui PR: 876
File: internal/logstream/hub_test.go:188-192
Timestamp: 2025-12-28T18:44:10.496Z
Learning: In Go 1.25 (Aug 2025), use wg.Go(func()) to spawn a goroutine and automate the Add/Done lifecycle. Replace manual patterns like wg.Add(1); go func(){ defer wg.Done(); ... }() with wg.Go(func(){ ... }). Ensure the codebase builds with Go 1.25+ and apply this in relevant Go files (e.g., internal/logstream/hub_test.go). If targeting older Go versions, maintain the existing pattern.

Applied to files:

  • internal/backups/service.go
🧬 Code graph analysis (1)
internal/backups/service.go (1)
internal/models/backups.go (4)
  • BackupRunStatusPending (59-59)
  • BackupRunStatusRunning (60-60)
  • BackupRunStatusFailed (62-62)
  • BackupRunStatusCanceled (63-63)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run tests
🔇 Additional comments (5)
internal/backups/service.go (5)

40-44: LGTM!

The new configuration fields are well-typed and appropriately exposed for external configuration.


118-123: LGTM!

The default values (10m cooldown, 200ms throttle) follow the existing pattern and are reasonable starting points.


557-565: LGTM!

Proper ticker lifecycle management with conditional creation and deferred cleanup. The nil check before stopping prevents panics.


662-668: Throttle correctly paces exports and respects cancellation.

The throttle is applied before each ExportTorrent call, preventing rapid-fire requests to qBittorrent. Note that this introduces a delay before the first export as well; if you want to avoid the initial delay, move the throttle wait to after the export. However, for preventing crashes, the current approach is safer.


1664-1667: LGTM!

Clean accessor method for the data directory configuration.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@internal/backups/service.go`:
- Around line 315-335: The switch on r.Status in the runs loop is missing an
explicit case for models.BackupRunStatusSuccess which fails exhaustive-switch
checks; add a case for models.BackupRunStatusSuccess (or a default) inside that
switch in the short-circuit logic (the block that iterates over runs and checks
Pending/Running/Failed/Canceled) and make it a no-op or explicitly handle it
(e.g., `case models.BackupRunStatusSuccess: // fallthrough/no-op`) so the
exhaustive linter check passes while preserving the existing behavior that
non-pending/running/failed statuses continue past the cooldown logic.

@s0up4200 s0up4200 merged commit a72715e into develop Feb 12, 2026
13 checks passed
@s0up4200 s0up4200 deleted the codex/fix-qbittorrent-crash-during-backups branch February 12, 2026 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Backups cause qbittorrent to crash

1 participant