Docker Mode
Docker mode provides single-process services for running bots in containers. This is the recommended deployment for local development and small-to-medium deployments (up to ~1000 bots per host).
Architecture
Docker mode uses a unified execute architecture where each bot container is self-managing. The runtime services (bot-runner and bot-scheduler) only handle container lifecycle - starting, stopping, and restarting containers. All the complexity of code download, state persistence, and log streaming is delegated to the runtime execute command running inside each container.
Services
bot-runner manages live trading bots - containers that run continuously until stopped. The service monitors container health and restarts failed containers through the reconciliation loop.
bot-scheduler manages cron-based scheduled bots. It evaluates cron expressions to determine when bots should run, then starts containers that execute once and terminate.
query-server handles query requests on port 9477. For realtime bots, it proxies to the container's query server on port 9476. For scheduled bots, it spawns ephemeral containers.
How It Works
The Reconciliation Loop
Both BotService and ScheduleService use a reconciliation pattern. Every 30 seconds (configurable), the service queries MongoDB for the desired state - which bots should be running - and compares it against the actual state from Docker. If a bot should be running but isn't, the service starts it. If a container is running but the bot was disabled, the service stops it. If the configuration changed, the service restarts the container.
NATS integration is optional but recommended. Without NATS, changes only take effect at the next reconciliation interval. With NATS, the service receives events immediately and can act on them right away.
Container Execution
When a container starts, it runs runtime execute which handles everything:
State Persistence
The daemon sync process periodically (every 60s) computes a hash of the state directory and uploads changes to MinIO when detected. Logs are also synced periodically.
For scheduled bots, the daemon also watches for a "done" file. When the bot completes and writes its exit code to this file, the daemon performs a final sync and then exits, allowing the container to terminate cleanly.
Query Execution
Realtime Bot Queries
For running bots with a query entrypoint, runtime execute starts a query server subprocess on port 9476. Queries are proxied to this server:
- QueryServer (port 9477) receives HTTP request
- QueryResolver finds the bot and its container
- QueryHandler proxies to container IP:9476 (the query server subprocess)
- Response returned (~10-50ms latency)
Scheduled Bot Queries
For scheduled bots (not currently running), queries spawn ephemeral containers:
- QueryServer receives request
- QueryResolver finds the bot configuration
- QueryHandler builds executable with
QUERY_PATHandQUERY_PARAMSenv vars - DockerRunner starts ephemeral container
- Container runs query mode, returns JSON result
- Container terminates (~1-3s latency)
Service State
The services maintain in-memory state to track running containers:
- RunningBot: Tracks each bot's container ID, status, start time, and restart count
- ServiceState: Thread-safe map of botID → RunningBot with metrics
- Statuses: "starting", "running", "stopping", "failed"
This enables the reconciliation loop to compare desired state (MongoDB) with actual state (running containers) and take corrective action.
Quick Start
Using Docker Compose:
cd docker
make upThis starts all services including bot-runner, bot-scheduler, and query-server. Runtime images are built automatically.
Environment Variables
Required
MONGO_URI=mongodb://localhost:27017 # MongoDB connection
MINIO_ENDPOINT=localhost:9000 # MinIO endpoint
MINIO_ACCESS_KEY=the0admin # MinIO access key
MINIO_SECRET_KEY=the0password # MinIO secret keyOptional
NATS_URL=nats://localhost:4222 # NATS for real-time eventsCapacity
| Metric | Single Process |
|---|---|
| Bots managed | 10,000+ |
| Memory overhead | ~100MB for 1000 bots |
| Goroutines | 1 per bot + collectors |
| Docker limit | ~1000 containers/host |
If you need more than 1000 bots: use Kubernetes mode.