I have been launching one product a month for the last nine months, and the thing that kept me up at night was whether the nine before it were still up, which is a stupid thing to lose sleep over until you actually have eleven of them.

I did not have any uptime monitoring at all for most of that year, because as a self-hoster the question eats itself. If I run the checker on the same box as the sites, the power cut takes out the thing that was supposed to tell me about the power cut. So I rent a VPS somewhere, and now I have another server to patch and another bill to pay, and I still cannot tell whether the site is down or the checker is. I have done that dance enough times to know it always ends with me refreshing a page I do not trust. Then one evening I was staring at the Cloudflare dashboard and realised the network was already in front of a lot of what I run, and it stays up most days because half the internet assumes it will, so I put the checker there instead, on Workers with D1 for storage, and called it Vigil. It still disappears when Cloudflare does, so this is a shorter chain and not a solved one, but I will take a network that is better maintained than my self-hosted server.

A cron fires every five minutes and picks up whatever monitors are due, then probes them over HTTP or TCP at the same time, each one racing its own deadline so a single hanging endpoint cannot hold the tick hostage. Results land in D1 as downtime windows and hourly samples, webhooks go out on state changes, recovery always fires, and a down alert waits for grace_min consecutive failures because I do not want a page for a two second blip. The status page is plain HTML with no frontend framework, plus a small JSON API and an SVG badge for the README, and the history bars show gaps as gaps so a monitor that joined last week does not get a fake 100% uptime for the week before it existed. The bit I have ended up loving is the colo, which is Cloudflare’s word for the data centre that answered the request. Every sample records it, so when the internet line in Bagdogra is having a bad monsoon I can see whether the site was slow or whether my road to the site was slow. Workers choose the colo and I can only display it, so the edge is somebody else’s computer even when it feels like mine. It cannot do ICMP or UDP either, since Workers have no raw sockets, so anything exotic needs a small prober outside reporting back over HTTP.

Vigil is Rust compiled to WebAssembly, and I have not read most of the code. This is the first project of my life where that is true. I have used Rust in small pieces before, an embedding engine here and there, the kind where you need to chew through a lot of CPU or memory and you paste a crate into a Node app and pray, but I have never built an application in it. I look at Rust and my eyes slide off. Lifetimes, trait bounds, impl blocks, the ampersands everywhere; I have no idea how people type this for a living. The code is genuinely horrible to look at, at least to me.

Thanks to agents I can write Rust without writing Rust. I described what I wanted, the agent wrote the types, and I reviewed what it did through the tests and the config and the pages and the deploy logs. That is a different kind of review, and I should be honest that I have not read this codebase the way I read my JavaScript. I read it the way I read a contract I did not draft.

What made that tolerable is the shape of the repo, since vigil-core is pure logic with no I/O, so the verdicts and rollups and labels can be tested on my laptop without a Worker or a database, and the worker crate is a thin shell that fetches and stores and renders. There are 139 tests in there now, most of which I did not write, and I have read what they assert, which is the only reason I can sleep. The workspace also forbids unsafe code, which I did not ask for and am glad the agent did. One of those tests exists because a single line in the chart query compared rn % stride = 1, which matches nothing when stride is 1, which meant every short-range chart went blank in production while the database was full of perfectly good samples. In plain English; the chart asked for every sample whose rank was one more than a multiple of the stride, and when the stride was one it asked for nothing at all. The fix was to subtract one before the modulo, and the harness now runs the shipped SQL text against bundled SQLite in memory, because D1 is SQLite and a query that only lives inside a string is a query nobody is testing. I would never have found that by staring at Rust, because I cannot stare at Rust.

Then there is the speed, and boy oh boy, this is the part I cannot shut up about. A single check comes in under 5 milliseconds of CPU time and under 100 milliseconds of wall clock in my logs. Ten milliseconds for a thing that wakes up, resolves a name, opens a socket, reads a response and writes a row. I keep asking how is that even possible. Some of it is Cloudflare, because the wasm module instantiates in a few milliseconds and there is no container to boot and no runtime to warm up, and some of it is Rust doing the actual work in almost no instructions. I am not going to pretend I understand every allocation, but I understand the graph, and the graph is flat. Rust is so fast man, and I say that as someone who cannot read it.

In the Node and Python things I have shipped, the boot and the ORM and the pool and the framework all eat the request before my code even runs, and here the check is the request. I keep the bundle small on purpose, opt-level = "z", LTO, one codegen unit, and strip = "debuginfo" because strip = true also strips the wasm target features section and wasm-bindgen fails with an externref error that took me an afternoon to understand. I also keep the fleet under roughly fifty monitors per minute, since the whole cron tick shares one CPU budget, and I would rather run a small fleet that reports honestly than a big one that gets throttled and lies by omission.

I posted about this along with a DNA joke on LinkedIn a few days back and nobody replied to the joke 😭. I said I want to replace my DNA with Rust. DNA is four letters on a sugar-phosphate backbone and it takes forever to patch a bug, and Rust will not compile a data race. If I could get that guarantee on my own cells I would trade the hydrocarbons tomorrow. I read biology as a layman, so treat that as a wish with error bars.

Under all the jokes, the wish is about time. I have a fixed number of years and I would like more attempts inside them, more products and more walks up the hill before the light goes. Every minute I do not spend waiting for a build or a cold start or a dashboard to load is a minute I can spend on something that actually happened, and speed is the only lever I have found that buys back time without asking anyone’s permission.

Vigil is open source at github.com/TroySK/Vigil, MIT or Apache-2.0. If you write Rust for a living, go read it and tell me what I got wrong, because I am the guy who arrived with an agent, a credit card and a compiler that somehow let me in. Tweet to me @troysk704 or open an issue. I check the status page every morning before my tea. Work is worship, and half of worship is showing up to see whether the thing you built is still standing.