fix(sync): R5 S2 — sync guards
- never prune subscriptions on an empty fetch: one anomalous empty-but-200 response wiped every subscription (and its deep_requested flag) in one run - push_playlist: stop after 5 consecutive write failures — a quota-dead or scope-revoked account otherwise burns 50 units per remaining item - RSS: raise RssError instead of returning [] on a transport/HTTP failure, so a failed poll no longer stamps last_rss_at and a 404 feed stops looking healthy - worker: exit when the schema never appears instead of "continuing" into a crash one call later
This commit is contained in:
+18
-8
@@ -93,24 +93,33 @@ def _parse_upload_date(raw) -> date | None:
|
||||
|
||||
# --- claim + recovery -----------------------------------------------------------------------
|
||||
|
||||
def _wait_for_schema(timeout: float = 300.0) -> None:
|
||||
"""Block until the download tables exist before doing any DB work.
|
||||
def _wait_for_schema(timeout: float = 300.0) -> bool:
|
||||
"""Block until the download tables exist before doing any DB work. Returns False if they never
|
||||
appeared (or we were asked to stop while waiting).
|
||||
|
||||
The API applies migrations on its OWN startup, and the worker is a separate container that may
|
||||
boot first (they start in parallel). Without this, the worker would hit a missing `download_jobs`
|
||||
table and crash-loop until the API's migrations land. Poll patiently instead."""
|
||||
table and crash-loop until the API's migrations land. Poll patiently instead — and if the schema
|
||||
is still absent when the timeout runs out, say so and let the caller exit, because "continuing"
|
||||
only moved the same crash one call further down (into `_recover_orphans`), where it read as an
|
||||
unrelated failure."""
|
||||
deadline = time.monotonic() + timeout
|
||||
while not _stop.is_set():
|
||||
try:
|
||||
with SessionLocal() as db:
|
||||
db.execute(text("SELECT 1 FROM download_jobs LIMIT 1"))
|
||||
return
|
||||
return True
|
||||
except Exception as exc: # noqa: BLE001 — table not migrated yet / DB not up yet
|
||||
if time.monotonic() > deadline:
|
||||
log.warning("download schema still absent after %ss; continuing: %s", timeout, str(exc)[:120])
|
||||
return
|
||||
log.error(
|
||||
"download schema still absent after %ss — the API's migrations have not landed; "
|
||||
"exiting so the container restarts: %s",
|
||||
timeout, str(exc)[:120],
|
||||
)
|
||||
return False
|
||||
log.info("waiting for the database schema (API migrations)…")
|
||||
_stop.wait(3.0)
|
||||
return False
|
||||
|
||||
|
||||
def _recover_orphans() -> None:
|
||||
@@ -719,8 +728,9 @@ def main() -> None:
|
||||
log.info("WORKER_ENABLED is off; worker exiting (nothing to do).")
|
||||
return
|
||||
|
||||
_wait_for_schema() # the API may still be applying migrations when we boot
|
||||
if _stop.is_set():
|
||||
# The API may still be applying migrations when we boot. If they never arrive, exit instead of
|
||||
# pressing on into a guaranteed crash — the container's restart policy retries the whole wait.
|
||||
if not _wait_for_schema():
|
||||
return
|
||||
_recover_orphans()
|
||||
n = max(1, settings.download_worker_concurrency)
|
||||
|
||||
Reference in New Issue
Block a user