A single NightOwl agent handles ~13,400 payloads/s on modest hardware — enough for most production Laravel apps. When you need more, scale horizontally rather than vertically: run several agents on the same box (or several boxes), fan ingest across them, and share the same PostgreSQL destination.Documentation Index
Fetch the complete documentation index at: https://docs.usenightowl.com/llms.txt
Use this file to discover all available pages before exploring further.
When you need more than one instance
- Your health dashboard shows buffer depth consistently climbing during peak hours.
- A single agent can’t keep ingest and drain aligned even after tuning drain workers.
- You want redundancy — if one agent crashes, the application shouldn’t lose telemetry while it restarts.
NIGHTOWL_DRAIN_WORKERS before adding instances.
Scaling drain workers first
Each agent runs one ingest loop plus N drain workers. Drain workers claim rows from the SQLite buffer atomically, so they never race.Running multiple agents on one host (Linux)
Linux’sSO_REUSEPORT lets multiple processes bind the same TCP port; the kernel distributes accepted connections across them. Start agents with NIGHTOWL_SO_REUSEPORT=true:
nightowl-agent@1, nightowl-agent@2). Each process gets its own SQLite buffer file but writes to the same PostgreSQL database.
Running multiple agents across hosts
For horizontal scaling across machines, put a TCP load balancer (HAProxy, nginx stream module, or a cloud LB) in front of the agent pool. Your application sends to the load balancer’s address:PostgreSQL and PgBouncer
Every agent instance opens a pool of PostgreSQL connections. Without pooling, N agents × M drain workers quickly exhaustsmax_connections. The shipped docker-compose.yml includes a PgBouncer container on port 6432:
Sizing math
A rough budget for capacity planning:| Component | Per-instance capacity |
|---|---|
| Ingest (TCP) | ~13,400 payloads/s |
| Drain (1 worker) | ~5,600 rows/s (COPY) |
| SQLite buffer | 100,000 rows max |
Verifying the fan-out
Open the health dashboard after starting the second agent. Each instance reports its own row in the Instances table with distinct process IDs, ingest rates, and buffer depths. The sum of the per-instance ingest rates should match your application’s outgoing traffic. If one instance is getting all the traffic, check thatSO_REUSEPORT is actually enabled — a common symptom is one agent doing 100% while the others sit at 0%.