diff --git a/examples/docker/README.md b/examples/docker/README.md index ea19ac26..9cf8c1d0 100644 --- a/examples/docker/README.md +++ b/examples/docker/README.md @@ -8,7 +8,12 @@ LanceDB allows exactly one writer + N readers per database URI, so the example runs the ingester and the MCP server as **two separate containers** sharing the same data volume: -- **docling-serve** - Document conversion and chunking service +- **docling-serve-1** / **docling-serve-2** - Two replicas of the + document conversion + chunking service. The ingester round-robins + jobs across them; running two means convert work overlaps and one + container restarting (e.g. for memory recycling) doesn't stall + ingest. Bumping to N replicas is the same pattern — duplicate the + service block and add the URL to `providers.docling_serve.base_url`. - **haiku-ingester** - Long-lived writer. Watches `/docs`, ingests new and changed files, queues retries, exposes the control plane on port 8765. - **haiku-rag** - Read-only MCP server on port 8001 for AI assistant @@ -79,7 +84,8 @@ curl http://localhost:8765/dlq ## Ports -- `5001` - docling-serve API (with UI enabled) +- `5001` - docling-serve replica 1 API (with UI enabled, debug only) +- `5002` - docling-serve replica 2 API (host port; container still listens on 5001) - `8001` - MCP server (read-only) - `8765` - ingester control plane (`/health`, `/jobs`, `/sources`, `/dlq`) diff --git a/examples/docker/docker-compose.yml b/examples/docker/docker-compose.yml index 43b29dac..ced8d224 100644 --- a/examples/docker/docker-compose.yml +++ b/examples/docker/docker-compose.yml @@ -1,9 +1,30 @@ services: - docling-serve: + # Two docling-serve replicas — the ingester round-robins jobs across them + # via the `providers.docling_serve.base_url` list in haiku.rag.yaml. Each + # serves the same image with the same env; running more than one is the + # supported scaling pattern for docling-serve since the upstream image + # processes one task at a time per instance by default. + docling-serve-1: image: quay.io/docling-project/docling-serve:latest - container_name: docling-serve + container_name: docling-serve-1 ports: - - "5001:5001" + - "5001:5001" # exposed on the host for ad-hoc debugging (5001) + environment: + - DOCLING_SERVE_ENABLE_UI=1 + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5001/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + start_interval: 5s + + docling-serve-2: + image: quay.io/docling-project/docling-serve:latest + container_name: docling-serve-2 + ports: + - "5002:5001" # host 5002 → container 5001 (debug only) environment: - DOCLING_SERVE_ENABLE_UI=1 restart: unless-stopped @@ -43,8 +64,13 @@ services: - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - VOYAGE_API_KEY=${VOYAGE_API_KEY} - CO_API_KEY=${CO_API_KEY} + # Logfire emits spans when this is set; stays silent (no telemetry) when unset. + # Set LOGFIRE_TOKEN in examples/docker/.env (gitignored) to enable. + - LOGFIRE_TOKEN=${LOGFIRE_TOKEN:-} depends_on: - docling-serve: + docling-serve-1: + condition: service_healthy + docling-serve-2: condition: service_healthy healthcheck: # No curl in the slim image; use Python's stdlib instead. diff --git a/examples/docker/haiku.rag.yaml.example b/examples/docker/haiku.rag.yaml.example index ecc785f6..129cdab8 100644 --- a/examples/docker/haiku.rag.yaml.example +++ b/examples/docker/haiku.rag.yaml.example @@ -31,7 +31,11 @@ processing: providers: docling_serve: - base_url: http://docling-serve:5001 + # Two replicas; ingester round-robins jobs across them, each call's + # submit / poll / result pinned to one instance. + base_url: + - http://docling-serve-1:5001 + - http://docling-serve-2:5001 api_key: "" ollama: base_url: http://host.docker.internal:11434