Skip to content

Refactor/consolidate backend services - #23

Open
Ayan-josh-05 wants to merge 4 commits into
fix/translation-startupfrom
refactor/consolidate-backend-services
Open

Refactor/consolidate backend services#23
Ayan-josh-05 wants to merge 4 commits into
fix/translation-startupfrom
refactor/consolidate-backend-services

Conversation

@Ayan-josh-05

@Ayan-josh-05 Ayan-josh-05 commented Aug 28, 2026

Copy link
Copy Markdown

Consolidate Backend Services into a Single Container

Summary

Collapses app, translation, field_mapping, ocr, and gateway from five separate containers into one (backend / backend-gpu), taking the stack from 9 containers down to 5.

None of the five services' own code changes — they keep running as independent FastAPI apps on their existing internal ports (8000/8001/8002/8010/8080), just co-located and launched together.

Also fixes a couple of build/runtime issues found while hardening this consolidated image, plus one pre-existing routing gap.

What Changed

Five Services, One Container (e748558)

scripts/start-combined.sh launches all five as separate uvicorn processes inside one container:

app            -> :8000
translation    -> :8001
field_mapping  -> :8002
ocr            -> :8010
gateway        -> :8080

If any one process dies, the script brings the whole container down (wait -n) rather than running silently degraded. This allows Docker Compose's restart policy to kick in instead of the container staying up in a half-broken state.

The root Dockerfile now installs all five services' dependencies. Each still has its own requirements.txt/pyproject.toml, installed as-is — this doesn't merge their code or dependency trees, it just installs all of them into one image.

docker-compose.yml drops from 5 backend service entries to 1 (backend/backend-gpu pair, same CPU/GPU opt-in pattern as ollama and surya-inference).

A new hf_cache volume persists the app's embedding model across container recreates instead of re-downloading it from HuggingFace every time.

Fixed a Pre-existing Routing Gap

The frontend called /cases through the gateway, but no route existed for it.

gateway/main.py now proxies /cases and /app/health to the app process, matching the existing OCR/translation/field-mapping proxy routes.

Ollama Ping Context-Size Mismatch (fca388f)

Ollama's num_ctx is fixed at llama-server process launch.

The translation health monitor (added in the previous branch) was pinging Ollama with different options than translate() uses (no num_ctx vs num_ctx=32768), which forced a full model reload (~250s) every time a ping and a translate call interleaved.

The monitor now reuses the same model_options for its ping, eliminating the reload thrashing.

Hardened the Consolidated Image (c2b9ac3)

  • Excluded .env from the Docker build context — it was previously getting baked into image layers via COPY . ..
  • Added restart: unless-stopped to db, ollama, and backend so a crash (which now brings down the whole combined container per the wait -n behavior above) actually restarts instead of staying down
  • Removed the four now-dead per-service Dockerfiles (gateway, ocr, translation, field_mapping) — nothing builds from them anymore now that everything routes through the root Dockerfile
  • Converted the root Dockerfile to a multi-stage build so gcc/libpq-dev and pip's build tooling stay in the build stage instead of shipping in the final runtime image

How to Test

cd lending-poc
docker compose up --build
  1. Confirm docker compose ps shows 5 containers instead of the previous 9:

    • backend
    • db
    • ollama
    • surya-inference
    • frontend
  2. Hit the gateway's proxied routes (/cases, /app/health, plus the existing OCR/translation/field-mapping paths) and confirm all five processes inside backend respond.

  3. Kill one of the five uvicorn processes inside the backend container (e.g. docker exec + kill) and confirm the whole container exits and gets restarted by Compose, rather than continuing to run degraded.

  4. Run a translate request followed by a health-check ping (or vice versa) back-to-back and confirm there's no ~250s stall from a model reload.

  5. Run docker history (or inspect image size) on the built backend image to confirm gcc/libpq-dev aren't present in the final layer.

Ayan-josh-05 and others added 4 commits August 28, 2026 14:15
…o one backend container

Collapses five separate service containers into one (backend/backend-gpu),
run as five uvicorn processes via scripts/start-combined.sh, reducing the
stack from 9 containers to 5. None of the five services' own code changes -
they keep running as independent FastAPI apps on their existing ports,
just co-located.

Also fixes a pre-existing gap where the frontend called /cases through the
gateway but no route existed for it - gateway/main.py now proxies /cases
and /app/health to the app process, matching the existing OCR/translation/
field-mapping routes. Adds an hf_cache volume so app's embedding model
survives container recreates instead of re-downloading from HuggingFace.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ollama's num_ctx is fixed at llama-server process launch, so pinging with
different options than translate() (no num_ctx vs num_ctx=32768) forced a
full model reload (~250s) on every ping/translate interleave. Reusing
model_options for the ping keeps context size consistent and eliminates
the reload thrashing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Exclude .env from the Docker build context so secrets stop getting
  baked into image layers via `COPY . .`.
- Add restart: unless-stopped to db/ollama/backend so a crashed process
  (start-combined.sh brings the whole container down on any one service
  dying) actually gets restarted instead of staying down.
- Remove the four per-service Dockerfiles (gateway, ocr, translation,
  field_mapping) left over from before the services were consolidated
  into the single root Dockerfile — nothing builds from them anymore.
- Convert the root Dockerfile to a multi-stage build so gcc/libpq-dev
  and pip's build tooling stay in the build stage instead of shipping
  in the final runtime image.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Explains the cpu/gpu profile pattern, network alias tricks, port-to-process
mapping on backend, and why depends_on uses required:false — including a
clarification that OCR's GPU work happens in surya-inference, not backend.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It significantly changes container/build/runtime orchestration (multi-service co-location + Compose refactor), which warrants final human validation of startup, health, and restart behavior end-to-end.

Pull request overview

This PR consolidates five backend FastAPI services (app, translation, field-mapping, OCR, gateway) into a single Docker image/container while keeping them as independent uvicorn processes on their existing ports, and updates the local Compose stack accordingly. It also closes a gateway routing gap for /cases and aligns the translation service’s Ollama health ping options with real translate calls to avoid expensive model reload thrashing.

Changes:

  • Add a combined entrypoint script to launch all five services in one container and exit the container if any process dies.
  • Refactor docker-compose.yml + root Dockerfile for a single backend/backend-gpu service (multi-stage build, consolidated dependency installs, new hf_cache volume, restart policies).
  • Update gateway routing to proxy /cases and /app/health, and fix translation Ollama ping to reuse translate-time model_options.
File summaries
File Description
lending-poc/scripts/start-combined.sh New entrypoint that starts five uvicorn processes and exits on first failure (wait -n).
lending-poc/README.md Documentation updates for the consolidated backend container and new routing behavior.
lending-poc/gateway/main.py Adds /cases and /app/health proxies; includes app in aggregated health.
lending-poc/gateway/Dockerfile Removes now-dead per-service Dockerfile.
lending-poc/field_mapping_poc/Dockerfile Removes now-dead per-service Dockerfile.
lending-poc/document_processing/translation/translation_service/adapters/ollama_adapter.py Reuses model_options in ping to prevent Ollama model reload thrash.
lending-poc/document_processing/translation/Dockerfile Removes now-dead per-service Dockerfile.
lending-poc/document_processing/ocr/Dockerfile Removes now-dead per-service Dockerfile.
lending-poc/Dockerfile Converts to multi-stage build and installs dependencies for all five services into a shared venv.
lending-poc/docker-compose.yml Collapses multiple backend services into backend/backend-gpu, adds restart policies and hf_cache.
lending-poc/.env.example Adds APP_REQUEST_TIMEOUT_SECONDS example.
lending-poc/.dockerignore Updates ignores for the new consolidated build context and excludes .env.
.gitignore Ignores CLAUDE.md.
Review details
  • Files reviewed: 12/13 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +3 to 7
backend services (OCR, translation, field-mapping, and the core app/cases
API).

Each backend module keeps running exactly as it already does today, in its
own process/venv, on its own internal port. This gateway does not import or
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants