← Notes

Paweł · 10 September 2026

Deployments without a server and without a hard sleep

The site sits on the network edge — there is no machine, no system to patch, no application pool. There is code, a database and an object store. A deployment means sending a package, not restarting a service.

Four of the five repositories build and deploy themselves after a push to the main branch. The fifth does not, and the reason is instructive.

One click that cannot be automated

Connecting automatic builds requires consent to access the repository, granted in the dashboard. The consent cannot be issued through the API — a deliberate safeguard, and hard to hold against anyone. The effect, though, is that one instance deployed by hand for weeks and regularly fell behind.

npm run build
cd .output/server
export CLOUDFLARE_API_TOKEN=... CLOUDFLARE_ACCOUNT_ID=...
rm -rf ../../.wrangler/deploy
npx wrangler@latest deploy -c wrangler.json
Manual deployment, in other words a prosthesis

The more general conclusion: every automation chain has one step that needs a human. It is worth knowing it by name, because that step decides how much you have really saved.

Deployment time is unpredictable

The first version of the verification script waited a fixed three and a half minutes. It worked until a deployment started taking forty seconds one time and eight minutes the next.

A hard sleep is always the wrong answer: either you wait too long, or you check a state that does not exist yet. We replaced it with polling every five seconds, with an exit condition on a change of the version identifier.

GET /accounts/<account>/workers/scripts/<worker>/versions?per_page=1
  -> result.items[0].metadata.created_on

# loop every 5-10 s, ALWAYS with a timeout and a clear message.
# A loop without a timeout is not patience, it is a bug.
An exit condition instead of guessing

Live verification, not from the logs

The build log says the build succeeded. It does not say that what was meant to start working actually works.

Nor can you check the engine version from the metadata address — it returns a build stamp, not a release number. The only reliable method is to fetch the page and look in it for a known string from the new feature.

curl --compressed -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" https://... \
  | grep -a 'known-string-from-the-new-feature'

# --compressed: the worker's response is compressed
# -A: without a User-Agent the bot filter sends back nothing
Two traps in one command

That second switch once cost me half an hour of checking why the page “had no content”. It did. Just not for me.