The nightly database backup (and "Run DB backup now") now sends pg_dump's
output straight to the off-site bucket as a multipart upload, with no copy
staged on this server. The object is named database/fabledcurator-<UTC
time>.dump and appears only once pg_dump has exited cleanly and every part
has landed; a failed dump aborts the upload and records pg_dump's last line.
Without a destination, dumps are written to /images/_backups as before.
- backup_s3: Upload (start / add part / complete / abort), with a busy or
silent bucket rested and asked again (15 s, 60 s, Retry-After obeyed), and
a Pacer that holds uploads to the new bandwidth limit.
- Settings: "Upload limit (Mbit/s)" on the destination card, 200 by default,
0 for none (migration 0120).
- pg_dump runs under nice (and ionice where installed), locally too.
- Backups card says where dumps go; the runs table gains "Saved to" and
shows a failed run's error. Off-site rows have no restore/tag/delete here:
restoring from the bucket is a later step (#6880).
Task #6878, milestone 586.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pytest 9.2.0 (released 2026-10-27, changelog #10644) changed how
monkeypatch.setattr restores an attribute the object does not hold in
its own __dict__: undo now deletes it instead of assigning the old value
back. Celery's conf serves every key through __getattr__, so undo called
delattr, the delete raised AttributeError, and pytest skipped the rest
of that test's undos. That made 53 teardown errors across six files
(cleanup API, task-run signals, tasks admin, backup, library audit, the
soft-limit salvage test), and could leak patches into later tests.
CI installs pytest unpinned, so the first run after the release picked it
up: the weekly base refresh of main, 2026-11-01, and every run since. The
gate held, so nothing was published.
tests/conftest.py gains `celery_conf(**values)`: it records each key's
value through conf[key], writes with conf.update(), and restores the
saved values after the test. The six files use it.
Task #6864.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DB backup polish (plan-task #764 Q3):
- pg_dump now uses custom format (-Fc): compressed (much smaller on NFS) and
restored via pg_restore. Artifact extension .sql → .dump; restore_db swaps
psql -f for pg_restore -d. BackupRun.sql_path field name kept (it's just the
db artifact path).
- Reconcile the subprocess guardrails: the DB timeout was 720s with a stale
'Celery soft is 10 min' comment, but backup_db_task's soft limit is actually
1800s — so the bounded-kill fired 18 min early. Set DB=1700s / images=21000s,
each just under its task's Celery soft limit so _run_bounded stays the
primary guard (an NFS D-state hang defeats Celery's own SIGKILL).
Real shrink of the DB is the #764 prune; this makes each dump smaller/faster
on top of that.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#739 — DB backups hung on NFS in uninterruptible D-state, defeating the 12-min
subprocess timeout AND Celery's hard limit, so a stuck pg_dump held the
concurrency-1 maintenance_long lane for hours — starving normalize_tags,
re-extract, audits, and the new series rescan (which is why #740 "never
applied"). Three fixes:
- _run_bounded: Popen + bounded post-kill reap; if the child is unkillable
(D-state) we stop waiting and re-raise TimeoutExpired, freeing the slot. The
orphan is reaped by the OS once its syscall clears.
- backup_db dumps to a LOCAL temp file then moves the finished .sql to the
(NFS) _backups dir — pg_dump's long phase is now a DB-socket wait + local
writes (killable) instead of an NFS write that hangs. backup_images keeps
bounded-kill (too big to stage locally).
- recover_stalled_backup_runs: split the stall window — db 40 min (was sharing
images' 7h), so a hung DB backup is flipped to error promptly.
#740 — Standardize tag casing showed "0 groups to change" the instant it was
clicked: onNormCommit overwrote the preview with zeros. Keep the real preview
visible and disable the button while queued; backend apply was already correct.
Tests: fake subprocess.Popen alongside run; bounded-kill fail-fast; local-temp
target; per-kind stall sweep.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>