fix(worker): survive startup race — wrap poll in try/except, add restart policy and backend healthcheck dependency
- Poll loop body is now wrapped in outer try/except so UndefinedTable (or any transient DB error) logs a warning and retries after poll_interval instead of killing the worker process. - docker-compose: worker gets `restart: unless-stopped` so Docker recovers it automatically on any unexpected exit. - docker-compose: worker `depends_on` now includes `backend: condition: service_healthy` so it waits for the backend (which runs migrations) to be ready before polling. Fixes DAP-40. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,7 @@ services:
|
||||
|
||||
worker:
|
||||
build: ./worker
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
DATABASE_URL: postgresql://kino:${DB_PASSWORD:-kino}@db:5432/kino
|
||||
MEDIA_PATH: /media
|
||||
@@ -48,6 +49,8 @@ services:
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
backend:
|
||||
condition: service_healthy
|
||||
|
||||
frontend:
|
||||
build: ./frontend
|
||||
|
||||
@@ -86,18 +86,22 @@ def process_job(db: Session, dl: Download) -> None:
|
||||
def run() -> None:
|
||||
log.info("Worker started, polling every %ds", settings.poll_interval)
|
||||
while True:
|
||||
with Session(engine) as db:
|
||||
pending = db.execute(
|
||||
select(Download).where(Download.status == DownloadStatus.pending).limit(1)
|
||||
).scalar_one_or_none()
|
||||
if pending:
|
||||
try:
|
||||
process_job(db, pending)
|
||||
except Exception as exc:
|
||||
log.error("Job %d failed: %s", pending.id, exc)
|
||||
pending.status = DownloadStatus.failed
|
||||
pending.error = str(exc)
|
||||
db.commit()
|
||||
try:
|
||||
with Session(engine) as db:
|
||||
pending = db.execute(
|
||||
select(Download).where(Download.status == DownloadStatus.pending).limit(1)
|
||||
).scalar_one_or_none()
|
||||
if pending:
|
||||
try:
|
||||
process_job(db, pending)
|
||||
except Exception as exc:
|
||||
log.error("Job %d failed: %s", pending.id, exc)
|
||||
pending.status = DownloadStatus.failed
|
||||
pending.error = str(exc)
|
||||
db.commit()
|
||||
except Exception as exc:
|
||||
# Transient errors (e.g. table not yet created, DB not ready) — backoff and retry
|
||||
log.warning("Poll error (will retry): %s", exc)
|
||||
time.sleep(settings.poll_interval)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user