oo-workers is the open-source slice of ObserveOne: the engine, the scheduler, and a minimal admin UI, all running in one docker compose up. This is the first post in a series tracing how it got built, in roughly the order it actually shipped. We start where the project did, with a single commit that stood up the engine.
The first commit#
The opening commit was the whole loop in miniature: BullMQ job queues on Redis, the Bun runtime, Postgres for state, a tiny SQL migration runner, and a JSONPath-aware assertion engine. Three monitor types existed at that point (URL, API, and Playwright browser checks), with the schema and processors to run them. Everything since has been widening that loop, not replacing it.
The stack, and why#
Bun for the runtime. No separate compile step, and a built-in bun:sql client meant Postgres access with no ORM and no driver to wire up. For a small worker process that mostly does IO, that cut a lot of setup.
Postgres for state. Monitors, their assertions, and every execution row live here. A plain .sql migration runner applies schema changes on boot, so a fresh docker compose up self-migrates with nothing to run by hand.
BullMQ on Redis for the work. Each monitor type gets its own queue, so a slow batch of browser checks never starves quick URL pings. Workers pull jobs concurrently, and concurrency is tunable per type through env (URL probes default to 20 at once, browser checks to 5, since a headless browser costs far more than an HTTP GET).
Playwright for browser checks. The script you run is a real .spec.ts, the same code a team already writes for end-to-end tests, stored and executed as-is rather than through a custom DSL.
How a check runs#
The scheduler runs in the same process as the workers and ticks every 5 seconds. Each tick it asks Postgres which monitors are due (by interval_seconds and last run), enqueues those, and goes back to sleep. The workers pick the jobs up, run the probe, evaluate assertions, and write an execution row. The dashboard reads those rows. That is the entire engine: tick, enqueue, run, record.
Keeping the scheduler in-process with the workers kept the first version to one moving part. It is honest to say that choice came back later, once multiple processes needed to share events, but for a single-box install it was the right place to start.
Next#
The engine shipped with three monitor types. The next post covers how that grew to eight, including heartbeats and the probes that do not speak HTTP at all.
oo-workers is the Apache-2.0, self-hosted slice of ObserveOne and runs in one docker compose up. The hosted product builds on the same engine and adds AI capabilities like Autopilot if you would rather not run the box yourself.