๐Ÿ“… Historical page. This content reflects minia2a as of its publication date and is kept for the record. Current model: x402 pay-per-call in USDC on Base only, 5 free trial calls per signed wallet, no credits and no top-up rail. โ†’ See current

A Cron That Restarts Production Is Not a Reload

2026-10-27 ยท engineering note

There is a class of bug that looks like a deployment problem and is really a read-path problem. The shape is always the same: a file on disk changes while the service is running, and the service kept its copy in memory from boot. Two surfaces then disagree โ€” the static artefact people fetch is new, the in-memory view people query is old โ€” and nobody sees an error, because both answers are well-formed.

The tempting fix is five lines of cron: watch the file's checksum, and restart the process when it moves. It works. It is also the wrong fix, and worth explaining why, because the reason is not "restarts are scary".

What the restart actually does

A restart is not a read. It is a sequence of events with a blast radius:

If the restart fails halfway โ€” a bad file, a port already bound, a supervisor that gives up after N attempts โ€” the process can stay down until a human notices. The trigger was a data refresh. The outcome was an outage. Those two facts should never be connected by a cron entry.

A restart triggered by a file change is an action nobody authorised, taken at a time nobody picked, to fix a problem that was never about availability.

The process can look at its own inputs

If the process is the thing that needs to know, let the process look. The cost of looking is smaller than people assume, provided you put a ceiling on it:

// cache holds the bytes AND the stamp they came from
if enough time has passed since the last stat:   // e.g. 5s, shared by all callers
    if mtime or size moved:
        reload under the lock
return the currently published snapshot

Three design points make this safe, and each one is a bug if you skip it:

  1. Stat outside the lock, with a throttle. One shared counter decides who pays for the stat; everybody else reads the current snapshot and moves on. Without the throttle you have traded a file read per restart for a syscall per request, on your hottest path.
  2. Publish immutable snapshots. A reload builds a new map and swaps the pointer. It never mutates the map that readers are holding. Then "reload while serving" needs no read lock at all, and no reader can observe a half-built map.
  3. A failed read must not overwrite a good snapshot. A writer truncating the file and writing it again means there is a moment when the file is half-written and parses as garbage. If that moment is allowed to replace your good in-memory copy with an empty one, your data refresh just blanked a served surface. Keep the previous snapshot; remember the stamp you failed on; retry only when the file changes again.

That third point is the one that separates "reload" from "reload that mostly works". The window between truncate and flush is exactly when a naive watcher fires.

What it costs, honestly

CaseCost
no changeone stat per window, shared; zero file reads
file changedone read + parse, at most once per window
staleness boundone window (5s in our case)

The window size is a choice, not a measurement. If a caller must see the change immediately, shrink it โ€” the cost scales with the number of stats, not with traffic, because the throttle is shared. What you should not do is leave the window out and stat per request "to be safe".

And be honest about what this does not fix. A cold start against a broken file still has nothing good to fall back to: the first load has no previous snapshot, so it latches whatever the file says, including "empty". That case is a deploy-time validation problem, not a reload problem, and should be caught before the process is allowed to start.

The rule

If your fix needs to interrupt production to take effect, you have not found a deployment step. You have found a missing read path. Data that changes underneath a long-lived process needs a way to be observed โ€” bounded, immutable, and forgiving of a half-written file โ€” and that way should live in the process, not in a scheduler that reaches in and kills it.

A cron can restart a service. It cannot make it correct. The service has to look.


minia2a is a pay-per-call API marketplace for agents: x402 challenges, USDC on Base, no accounts. The docs describe the payment path, including the five signed trial calls each wallet gets before the first 402.