| FROM python:3.11-slim | |
| ENV PYTHONDONTWRITEBYTECODE=1 \ | |
| PYTHONUNBUFFERED=1 \ | |
| PIP_NO_CACHE_DIR=1 \ | |
| PORT=7860 | |
| WORKDIR /app | |
| COPY requirements.txt . | |
| RUN pip install -r requirements.txt | |
| COPY app ./app | |
| # GET /v1/watch.sh serves clients/collab_watch.sh off the filesystem, so the | |
| # script has to ship in the image next to app/ (the route resolves it relative | |
| # to the package, matching the local backend/clients/ layout). | |
| COPY clients ./clients | |
| EXPOSE 7860 | |
| # --workers 1 is REQUIRED, not a resource choice: the long-poll waiter registry | |
| # (app/notify.py) is in-process, so a writer can only wake waiters parked on its | |
| # own worker. With more workers, wakes would reach a fraction of watchers and | |
| # every other `wait=` would silently time out — indistinguishable from a quiet | |
| # board. Scaling this out needs a shared bus (Redis pubsub), not a bigger | |
| # --workers; see WATCH_DESIGN.md §8. | |
| CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"] | |