Runtime Topology
This repository supports more than one runtime path, but the topology is always explicit.
The goal is to make it obvious which processes own:
- HTTP entry
- Laravel request handling
- queues
- scheduling
- realtime broadcasting
- cache and database state
1. Default production topology
The baseline production path is the docker-compose.production.yml stack.
Core services:
nginx: edge HTTP serverapp: Laravel API via PHP-FPMmysql: relational databaseredis: cache, queues, and transient runtime statehorizon: queue processingscheduler: scheduled command looppulse-worker: Pulse ingestion workerreverb: websocket/broadcast runtime
This path is the default because it is the least surprising for contributors and operators.
2. Octane topology
The alternative runtime path is docker-compose.octane.yml.
Core services:
octane: Laravel Octane + RoadRunner HTTP runtimemysqlredishorizonschedulerpulse-workerreverb
The main difference is that PHP-FPM and nginx are replaced by the long-lived Octane worker runtime.
Use this path when you explicitly want:
- RoadRunner-based HTTP serving
- long-lived worker performance
- runtime parity with Octane-specific deployments
3. Why the two topologies both exist
This repository does not force Octane everywhere.
That is intentional:
php-fpm + nginxremains the lowest-friction defaultOctane + RoadRunneris available as an explicit runtime choice- both paths are covered by CI smokes so they stay honest
This keeps the project practical for contributors while still supporting high-performance deployments.
4. Reverb in the topology
Realtime is kept as a separate runtime concern.
reverb is not collapsed into the HTTP process because that would make local and production behavior harder to reason about.
The expected model is:
- Laravel app dispatches broadcast events
- Reverb handles websocket fan-out
- frontend clients connect to the Reverb endpoint
That separation keeps the topology understandable and closer to real deployment behavior.
5. Queue and scheduler separation
Queue and scheduler responsibilities are not hidden inside the web process.
This repository keeps them explicit:
horizonowns queue executionschedulerownsschedule:runpulse-workerowns Pulse stream ingestion
That makes failure modes easier to isolate and keeps runtime observability clearer.
6. Health probe expectations
Different topology layers support different levels of health checking:
- container boot probes confirm the runtime process starts
- Laravel bootstrap probes confirm Artisan can initialize the app
- route-level probes confirm HTTP entry and Laravel request handling are live
That is why CI includes multiple smokes instead of a single generic check.
7. Recommended operator mental model
Think about runtime in layers:
- artifact integrity
- process boot
- Laravel bootstrap
- HTTP health
- queue/realtime/scheduler behavior
If you treat runtime as a single opaque container, debugging gets harder fast.