Documentation
¶
Overview ¶
Package readiness provides a readiness-probe endpoint for the express framework. It exposes a single well-known path (defaulting to "/readyz") that answers 200 "ready" when the application reports itself ready to serve traffic and 503 "not ready" otherwise; requests to any other path are left untouched and continue down the chain. It ports the readiness-gating concept that Node process managers such as terminus and lightship attach to an HTTP server, where an orchestrator (Kubernetes, a load balancer, a service mesh) polls the endpoint and only routes live traffic to instances that report themselves ready.
Use it to separate "the process is up" from "the process should receive requests." A server may be running yet still be warming a cache, replaying a migration, draining connections before shutdown, or waiting on a downstream dependency; during those windows the readiness probe should fail so the orchestrator holds traffic back without killing the pod (that is the job of a separate liveness probe). Because the Ready callback is evaluated on every probe, the same endpoint reflects the current state and flips back to 200 the moment the application recovers, which the tests exercise directly.
Mechanically the middleware inspects req.Path() first. When the path does not match the configured Path it calls next() immediately and reads or writes nothing else, so it is safe to register globally via app.Use at the top of the chain ahead of routers and other middleware. When the path matches it short-circuits the chain: it invokes the Ready function and writes the response itself with res.Status(...).Send(...), never calling next(). It does not consult any request headers and emits a plain-text body, so it is deliberately dependency-free and cheap to call at a high probe frequency.
The behavior is governed by two options with sensible defaults. Path defaults to "/readyz" when left empty. Ready defaults to a function that always returns true when nil, so a zero-value Options yields an endpoint that is always ready — useful as a liveness-style stub. A ready probe returns HTTP 200 with the body "ready"; a failing probe returns HTTP 503 Service Unavailable with the body "not ready", the conventional signal that tells an orchestrator to stop sending traffic without treating the instance as dead. There is no allowance for HTTP method: any method hitting the path is probed, mirroring the permissive behavior of typical probe endpoints.
Parity with the Node originals is behavioral rather than structural. Libraries like terminus and lightship expose richer machinery — multiple named checks, graceful-shutdown hooks, signal handling, and JSON health documents — whereas this package distills the piece that matters for request gating: a single boolean predicate mapped onto 200/503 at a configurable path. Callers that need composite checks can aggregate them inside their own Ready function, keeping this middleware a thin, allocation-free adapter over the express handler signature.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func New ¶
New returns readiness middleware configured by opts.
Example ¶
ExampleNew wires the readiness probe into an application and drives it with httptest to show how the endpoint reflects application state. The middleware is registered globally via app.Use so it runs ahead of the router, and a closure-captured flag stands in for whatever real signal (cache warmed, migrations done) would gate traffic. The first probe is issued while the application reports itself not ready and therefore returns 503; the flag is then flipped and a second probe returns 200. Requests to other paths, such as "/", bypass the probe entirely and reach the normal route. The status codes and bodies are fully deterministic, so the example verifies them with an Output block.
package main
import (
"fmt"
"net/http/httptest"
"github.com/malcolmston/express"
"github.com/malcolmston/express/middleware/readiness"
)
func main() {
ready := false
app := express.New()
app.Use(readiness.New(readiness.Options{
Path: "/readyz",
Ready: func() bool { return ready },
}))
app.Get("/", func(req *express.Request, res *express.Response, next express.Next) {
res.Send("home")
})
probe := func() (int, string) {
rec := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/readyz", nil)
app.ServeHTTP(rec, req)
return rec.Code, rec.Body.String()
}
code, body := probe()
fmt.Printf("before: %d %s\n", code, body)
ready = true
code, body = probe()
fmt.Printf("after: %d %s\n", code, body)
rec := httptest.NewRecorder()
app.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
fmt.Printf("route: %d %s\n", rec.Code, rec.Body.String())
}
Output: before: 503 not ready after: 200 ready route: 200 home