Repository navigation
Anole 0.3.0
Anole 0.3.0 is the developer-experience release. My goal for it was that starting, configuring, testing and watching an Anole app feels as easy as it does on Express, Fiber or Bun.
zig fetch --save git+https://github.com/xuckless/anole#v0.3.0
What's new
- Settings,
.envfiles and deployment modes.anole.config.load(T, ...)reads typed settings from defaults, files and the environment..envfiles are read in development.environment(development or production) anddeployment(standalone, behind_proxy, anole_lb, platform) set sensible defaults that any explicit option overrides, and the server prints what they changed at startup. - Validation and typed handlers. Field rules on structs, all violations reported at once as a 422
problem+jsonfromreq.bind, andanole.In(.{ .path, .query, .headers, .body })for typed handler inputs. Route paths are checked at compile time. - Logging. JSON Lines logs by default in production, readable logs in development, and startup errors as two readable lines: what failed and how to fix it.
- Testing.
anole.testinggives an in-memory client for routes and middleware. - Resilience. Retries with backoff and jitter, retry budgets, and circuit breakers. PostgreSQL, Redis and MongoDB calls fail fast with 503 while their breaker is open.
- Messaging. A NATS client and my own Kafka client (produce, consumer groups, compression), both also in the C ABI.
- OpenAPI. An OpenAPI 3.1 document generated from typed routes, validator rules and protobuf, for REST, transcoded gRPC and Connect.
- The
anolecommand line.anole newscaffolds a project from templates (minimal, rest-postgres, realtime, grpc, full). Prebuilt binaries for five platforms are attached below, with SHA256SUMS. - A live console.
anole consoleattaches to a running app over a local socket and shows logs, requests, errors, connections, databases, WebSocket and HTTP/3 state, config and routes, and can reload or drain the app. It's on by default and costs nothing while nobody is attached. - Runtime gauges per executor in
/metrics. - C ABI 0.9, with everything above that a Node or Python app would use.
Breaking changes
req.bindvalidates by default: a JSON body whose values don't fit the type is now a 422 with the violations, not a 400.req.bindWithkeeps the old behaviour.- Route methods take their path at compile time. Use
app.addRoute(method, path, handler)for a path known only at run time. - WebSocket over HTTP/2 (RFC 8441) is now off by default. In my measurements it used about twice the CPU of WebSocket over HTTP/1.1 (#91). Turn it on with
http2.enable_connect_protocol = true. timeouts.keepalivedefaults to 75 s, up from 60 s, so it sits above the idle timeout of nginx and AWS load balancers.- The access log's JSON lines follow the shared log record (
timereplacests).
docs/migrating.md has every change with before and after code.
Performance
I compared 0.3.0 with 0.2.1 on my x86 Linux box: three rested rounds per case in rotating order. HTTP/1.1, HTTP/2, HTTP/3, PostgreSQL and WebSocket are all within noise of 0.2.1, and instructions per HTTP/1.1 request are within 0.4%. With the console enabled but nobody attached, HTTP/3 on io_uring is about 1.7% slower; I'll follow that up in #103.
Fixed along the way
- A NATS
connect()with reconnect off could report a failure although the connection had been made, when the server hung up right after the handshake. - Kafka now works with brokers that serve Produce v7 and ListOffsets v4, such as Redpanda 25.2.
Known issues
- On Windows, a development-only target, one test still hangs. I'll fix it in 0.3.1, together with an HTTP/3 client stall after a NAT rebinding mid-download (#98).
The full list is in CHANGELOG.md.