Deployment topology
Factflow’s server is a single Python process (FastAPI + uvicorn) that talks to three external systems: a message broker, PostgreSQL, and an object store. This page is the physical architecture.
Production topology
Section titled “Production topology”flowchart TB subgraph Client[Clients] CLI[factflow CLI] WEB[Browser — React frontend] HK[Webhook consumers] end subgraph Ingress LB[Load balancer / ingress] AUTH[SSO auth layer] end subgraph Server[Factflow server process] API[FastAPI HTTP layer] CON[ServiceContainer DI] MGR[OrchestratorManager] CHAT[Chat service] WHK[Webhook dispatcher] end subgraph Infra[External systems] BR[Message broker<br/>Artemis / RabbitMQ / Pulsar] DB[(PostgreSQL 18<br/>+ pgvector)] ST[Object storage<br/>filesystem or MinIO/S3] LLM[LLM providers<br/>OpenAI / Anthropic / Bedrock] end CLI --> LB WEB --> LB LB --> AUTH AUTH --> API API --> CON CON --> MGR CON --> CHAT CON --> WHK MGR -.publish/subscribe.-> BR MGR -.read/write.-> ST MGR -.commit.-> DB CHAT -.embed/complete.-> LLM CHAT -.vector search.-> DB WHK -.POST.-> HK style Server fill:#f0fdf4,stroke:#16a34a,color:#111 style Infra fill:#e6f2ff,stroke:#2563eb,color:#111
What each component owns
Section titled “What each component owns”| Component | Responsibilities |
|---|---|
| Load balancer | TLS termination, rate limiting, request routing |
| SSO auth layer | DNB SSO headers → user identity (server trusts forwarded headers) |
| FastAPI HTTP layer | 91 endpoints, SSE streaming, OpenAPI spec |
| ServiceContainer | DI registry — wires every service, owns lifecycle |
| OrchestratorManager | All running executions in this process |
| Chat service | RAG, stateful threads, streaming responses |
| Webhook dispatcher | Listens to storage/execution events, POSTs to subscribed URLs, retries |
| Message broker | Durable queues + topics across all executions |
| PostgreSQL | Pipeline configs, executions, lineage, embeddings, chat, webhook deliveries |
| Object storage | Every pipeline artefact — HTML, markdown, segments, binaries |
| LLM providers | External SaaS or local inference endpoints |
Embedded mode (local development)
Section titled “Embedded mode (local development)”For local development, Factflow ships an embedded mode that auto-provisions infrastructure via Docker:
flowchart TB subgraph Dev[Developer laptop] C[factflow CLI] --> E[Embedded server] E --> EPG[Postgres container] E --> EBR[Artemis container] E --> FS[./output/storage] E -.optional.-> LLM[Real LLM APIs via env vars] end style Dev fill:#fef3c7,stroke:#d97706,color:#111
Startup command:
cd backenduv run python -m factflow_server serve --embeddedWhat happens on startup:
- Server process starts uvicorn on port 8000
- Container connects to a testcontainers-managed Postgres 18 instance
- Starts an in-process ActiveMQ Artemis broker (or spins up a container)
- Points storage at a local
./output/storage/directory - Reads LLM keys from environment if present
- Validates every shipped YAML under
backend/config/pipelines/ - Runs orchestrator manager ready to accept executions
Horizontal scaling
Section titled “Horizontal scaling”Factflow does not today support multiple server processes coordinating on executions. The OrchestratorManager is process-local; a second server process wouldn’t see or manage the first’s running executions.
Horizontal scaling happens at the request-handling layer — run multiple server instances behind a load balancer, each responsible for its own executions. Sticky execution-id routing via ingress is required so status queries hit the server that owns the execution.
flowchart TB LB[Load balancer<br/>sticky on execution_id] LB --> S1[Server 1<br/>owns execs A, B] LB --> S2[Server 2<br/>owns execs C, D] LB --> S3[Server 3<br/>owns execs E, F] S1 -.shared.-> BR[(Broker)] S2 -.shared.-> BR S3 -.shared.-> BR S1 -.shared.-> DB[(Postgres)] S2 -.shared.-> DB S3 -.shared.-> DB S1 -.shared.-> ST[(Storage)] S2 -.shared.-> ST S3 -.shared.-> ST
Multi-process coordination (cross-process OrchestratorManager) is a possible future feature but not required today at DNB scale.
What can fail independently
Section titled “What can fail independently”Service dependencies are decoupled:
| Dependency fails | Effect |
|---|---|
| Broker | Executions stall (publish/subscribe fails). New executions fail to start. Running ones pause. |
| PostgreSQL | Everything halts. Config lookups, lineage commits, execution CRUD all fail. |
| Storage | Adapters that persist artefacts fail. Read-side replay / download fails. |
| One LLM provider | Adapters using that provider fail. Others continue. Factory routes to configured alternatives if set. |
Graceful degradation policies are adapter-specific. Circuit breakers open on repeated adapter failure; messages route to DLQ.
Networking and ports
Section titled “Networking and ports”- 8000 — server HTTP (unless overridden via
--port) - 4321 — docsite dev server (separate — not a server port)
- 5432 — PostgreSQL
- 61613 — Artemis STOMP
- 5672 — RabbitMQ AMQP
- 6650 — Pulsar
- 9000 / 9001 — MinIO API / console
All internal except the server port, which sits behind ingress.
Deployment targets
Section titled “Deployment targets”Factflow deploys as a Docker container. Typical targets:
- AWS — ECS/Fargate + RDS Postgres + S3 + managed message broker (or self-hosted Artemis on EC2)
- Azure — Container Apps + Azure Database for PostgreSQL + Azure Blob Storage
- On-prem — Kubernetes with self-managed Postgres + MinIO + Artemis
Chromium-dependent workflows (web_crawler adapter) require the unclecode/crawl4ai base image rather than the slim Python base.
Related
Section titled “Related”- Execution flow — the runtime that lives inside the server
- Package map — what compiles into the server binary
- Guides / Queue Protocol — broker choices and trade-offs
- Guides / Storage Protocol — fs vs MinIO trade-offs