Declare tenacity - undeclared import crashed the container on boot

app/services/enrichment/barcode/retry.py imports tenacity at module scope,
and that module is on app/main.py's import path (main -> store_catalog router
-> store_catalog_pipeline -> barcode enrichment -> sources -> retry). tenacity
was in no requirements file, so the deployed image exited 1 during startup:

    File "/app/app/main.py", line 33, in <module>
        from app.api.routers import store_catalog
    ...
    File "/app/app/services/enrichment/barcode/retry.py", line 16
        from tenacity import (
    ModuleNotFoundError: No module named 'tenacity'

This surfaced as "100% CPU", not as a crash, which is why it was mis-read.
uvicorn never bound a socket, Swarm restarted the task, and each restart
re-ran the ~21s of eager pandas/scipy/sklearn imports that the analytics,
recommendations and nutrition routers pull in at module scope. On this
1-vCPU host that loop pins the only core indefinitely.

retry.py's own docstring asserted tenacity was "already a project dependency
(see requirements.txt)". It never was - corrected to say the opposite, and to
record that it is a hard startup dependency rather than an optional extra.

Verified on the deployed image, not just locally: with tenacity present the
container reaches health=healthy with restarts=0, and /, /api/health,
/api/brands, /api/system/status and /docs all return 200. Idle cost is
0.16% CPU / 168MiB. An AST scan of every import in app/, cli/, scripts/ and
serve.py against the image finds no other missing module (playwright is the
one remaining absence and is deliberate - commented out in requirements.txt
and imported lazily inside a function).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7bVBpxH4AbJtK7Kp3MzDR
This commit is contained in:
Suriyakumarvijayanayagam
2026-08-25 15:23:06 +05:30
parent 1b347f91db
commit a9ab1fcf71
2 changed files with 14 additions and 2 deletions

View File

@@ -1,8 +1,10 @@
"""
Configurable retry-with-exponential-backoff for barcode source calls.
Built on `tenacity`, already a project dependency (see requirements.txt -
used elsewhere for httpx-based retries). Only retries on genuinely
Built on `tenacity`, declared in requirements.txt. The import below is at
module scope and this module sits on app/main.py's import path, so tenacity
is a hard startup dependency, not an optional extra - without it the
container exits 1 before uvicorn binds. Only retries on genuinely
transient failures (network/timeout errors); a malformed response or a
"no results" outcome is not retried, since retrying those wastes the
source's rate-limit budget for no benefit (relevant for UPCItemDB's

View File

@@ -42,6 +42,16 @@ httpx>=0.27.2
# POST /api/catalog/generate to pull in NEW brands. If you only ever use
# the bundled seed data (scripts/seed_sample_data.py) + RAG chat/search,
# you can skip everything below this line.
# Retry/backoff for the barcode enrichment sources
# (app/services/enrichment/barcode/retry.py). This is NOT an optional extra:
# retry.py imports it at module scope, and that module is reached from
# app/main.py's own import of the store_catalog router - so a missing tenacity
# is not a degraded feature, it is the container exiting 1 on boot with
# ModuleNotFoundError before uvicorn ever binds a socket. Swarm then restarts
# it, and each restart re-runs ~21s of pandas/scipy/sklearn imports, which on a
# 1-vCPU host reads as pinned-at-100% CPU rather than as a crash.
tenacity>=8.2.3
beautifulsoup4>=4.12.3
lxml>=4.9.3
python-slugify>=8.0.4