Data & Enterprise
Enterprise Hardening
A production Zornux service validates itself at boot, degrades gracefully under failure, answers readiness probes, and shuts down cleanly. It's the difference between "it runs" and "an enterprise deploys it with confidence" — and it adds no new keywords.
Startup validation & fail-fast
An on startup hook runs before a service serves. A failed
require aborts the publish, so a misconfigured
instance never accepts a single request.
web Checkout
use AppConfig
on startup
require AppConfig.api_key otherwise "the API key must be configured"
end
end
require value [otherwise "message"] fails fast (ZX3300) when the value is false or nothing. It's an ordinary statement — use it at startup, or anywhere you need a precondition. It's recoverable with try.
Resilience policies
Wrap unreliable work in a named policy — a timeout, a
retry, and a circuit breaker — and apply
it with protect.
resilience PaymentGateway
timeout 5 seconds
retry 3 times waiting 1 second
break after 5 failures for 30 seconds
end
protect with PaymentGateway
charge = Payments.charge(order)
otherwise error
charge = 503
end
| Clause | Role |
|---|---|
timeout N seconds | Bound the work; over budget is a timeout (ZX3310). |
retry N times [waiting M seconds] | Re-run a recoverable failure or a timeout. |
break after N failures for M seconds | Circuit breaker: after N failed protects, reject calls for M seconds. |
The protected body is an isolated attempt (a give back ends it), so results flow out by mutating outer variables. Timeouts and the breaker's open window are measured on the deterministic virtual timeline, so resilience is reproducible and tests never flake.
The circuit breaker's three states
- Closed — calls run; consecutive failed protects are counted.
- Open — after the threshold, calls are rejected without running (
ZX3314), so the fallback handles them fast. - Half-open — once the window passes, the next call is a trial: success closes the circuit, failure re-opens it.
Graceful shutdown & readiness
A ready … end block registers GET /ready —
leaner than the liveness /health, it answers whether traffic
should come here. On the way out, the host drains and runs each service's
on shutdown hook.
web Api
ready
give back ok
end
on shutdown
log info "draining, goodbye"
end
end
Once shutdown begins, /ready answers 503 {"status":"shutting down"} so load balancers drain traffic away — while /health can stay green through the drain. Liveness and readiness are different questions.
Three probes, and who answers them
| Path | Answered by | Asks |
|---|---|---|
/live | the host itself | Is this process alive? |
/health | your health block, as a route | Is everything it depends on working? |
/ready | your ready block, as a route | Should traffic come here right now? |
The distinction matters to whatever is watching. /health and
/ready are ordinary routes, so they queue behind the work in
front of them; a process busy with a slow request can look dead to a
short-timeout probe. /live is answered by the host, so it stays
responsive regardless — which is why the generated container health check,
the generated proxy, and zornux deploy status all probe it.
Production diagnostics
show uptime_seconds() # seconds since start, on the injected clock
show memory_used() # bytes of memory in use
API hardening
Hardening composes with what Zornux already enforces: a typed route
auto-validates its body (400), and the
pipeline offers rate limits
(429), size limits (413), CORS, and
catch errors. A route can also wrap slow work in
protect with … for a per-route timeout, retry, and breaker.
Two of those defences run before a request costs you
anything. A request for a hostname this deployment does not serve is answered
421 on the accept thread — it takes neither a queue slot nor
any application time — and an over-large body is drained before its
413, so the caller reads the status instead of losing the
connection mid-upload. Which hostnames count is
accepted_hosts.
ZX3300 failed precondition, ZX3310 protect timeout, ZX3312 unknown policy, ZX3314 open circuit — all ZX3300–ZX3399, and the recoverable ones are handled by otherwise or a surrounding try.
Least-privilege runtime
A production instance should hold only the rights it needs to run.
--no-migrate opens the database
without migrate on open or lazy table creation,
so the runtime login can be granted zero DDL rights — schema is applied ahead of
it by a separate, privileged zornux db migrate step in the deploy
pipeline.
For certification-grade encryption, the capability-gated native kms module (encrypt, decrypt, reencrypt, describe_key, health, verify_access) reaches a managed KMS — commonly a private/VPC endpoint — without the general-purpose http module and without weakening anti-SSRF: a provider reaches only its one config-allowlisted endpoint through the guarded transport's scoped private-network allowance, and the cloud metadata address stays refused. It's off until a host arms a provider (fail-closed), so an ordinary program can't reach a KMS.
Built on background processing, concurrency, and the request pipeline.