Polling lives in internal/ext/watch, per the human's call to keep core under its ceiling rather than raise it a second time — which is what ADR-0041 said a second raise would mean. It is a poller, deletable without trace, and core stayed at 2671/2800. A settled change calls the same `rebuilder` that startup calls, because a reload path that differs from the startup path is a reload path that drifts. The index is an atomic.Pointer swapped whole, so a request reads the site that was current when it arrived instead of one being rebuilt underneath it — the alternative, mutating in place, is a data race with every in-flight request. Names, sizes and modification times, not contents: reading every file to detect a change costs more than the rebuild it triggers. Editor droppings are excluded, because saving in vim writes a swap file, a backup and the number 4913, and each would otherwise look like a change. A change must hold still for a moment first, since one save is often several operations. Verified against the running binary: a page 404s, the file appears, and five seconds later it serves — one "site root changed" in the log. Then three droppings written at once produced no rebuild at all. Two warnings fired and were fixed rather than silenced: `runServe` gave up the rebuild closure to `rebuilder`, and the fingerprint walk gave up its body to `record`, where three exclusions read as a list instead of as nesting. The Dockerfile ships the binary alone. The site root arrives as a volume and is never copied in — it is somebody's content repository with its own history (ADR-0011), so the image is the same for every site.
27 lines
1.0 KiB
Docker
27 lines
1.0 KiB
Docker
# One binary, a mounted site root, nothing else (ADR-0010).
|
|
#
|
|
# The site root is deliberately *not* copied in: it is somebody's content repository with its own git history
|
|
# (ADR-0011), so it arrives as a volume and the image stays the engine alone. That also means this image is the
|
|
# same for every site.
|
|
|
|
FROM golang:1.26 AS build
|
|
WORKDIR /src
|
|
# Modules first, so a content-only change never invalidates the dependency layer.
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
COPY . .
|
|
# Static, so the final image needs no libc and nothing to keep patched.
|
|
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /khosra ./cmd/khosra
|
|
|
|
FROM gcr.io/distroless/static-debian12:nonroot
|
|
COPY --from=build /khosra /khosra
|
|
|
|
# The site root is read-only to the engine: it only ever writes derivatives, and those go to the cache.
|
|
VOLUME ["/site", "/cache"]
|
|
ENV KHOSRA_SITE=/site
|
|
EXPOSE 8080
|
|
|
|
# Listens on every interface, because inside a container localhost is only the container.
|
|
ENTRYPOINT ["/khosra"]
|
|
CMD ["-addr", "0.0.0.0:8080", "-cache", "/cache"]
|