check / check (push) Successful in 12s
The root Dockerfile builds the only image; Dockerfile.backend is gone. Its stages: lint, a Go stage that runs the tests and builds netwatch-server, the node stage, and an nginx runtime. nginx serves dist/ on 8080 and proxies /api/ and /.well-known/healthcheck to the backend on 127.0.0.1:8081. bin/entrypoint.sh starts both, turns TERM or INT into a stop of both, and exits non-zero when either exits on its own. The backend runs as user netwatch and keeps reports on the /data volume. New setting BIND_ADDRESS (empty: every interface). STOPSIGNAL is SIGTERM, since the nginx image's SIGQUIT would miss the entrypoint. script/docker is the org model verbatim. Model: opus-5-5
71 lines
1.9 KiB
Go
71 lines
1.9 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go.uber.org/fx"
|
|
)
|
|
|
|
const (
|
|
readTimeout = 10 * time.Second
|
|
readHeaderTimeout = 5 * time.Second
|
|
idleTimeout = 60 * time.Second
|
|
maxHeaderBytes = 1 << 20 // 1 MiB
|
|
|
|
// requestTimeout (routes.go) is the single per-request
|
|
// processing budget, enforced by chi's middleware.Timeout.
|
|
// writeTimeout must exceed that budget so a handler can write
|
|
// its 503 when the chi timeout fires; if it were shorter the
|
|
// server would abort the write first and the chi budget would
|
|
// be unreachable dead configuration.
|
|
writeTimeout = requestTimeout + 5*time.Second
|
|
)
|
|
|
|
// newHTTPServer constructs the http.Server. It performs no I/O
|
|
// and does not start listening.
|
|
func (s *Server) newHTTPServer() *http.Server {
|
|
listenAddr := net.JoinHostPort(
|
|
s.params.Config.BindAddress,
|
|
strconv.Itoa(s.params.Config.Port),
|
|
)
|
|
|
|
return &http.Server{
|
|
Addr: listenAddr,
|
|
Handler: s,
|
|
MaxHeaderBytes: maxHeaderBytes,
|
|
ReadTimeout: readTimeout,
|
|
ReadHeaderTimeout: readHeaderTimeout,
|
|
WriteTimeout: writeTimeout,
|
|
IdleTimeout: idleTimeout,
|
|
}
|
|
}
|
|
|
|
// listenAndServe runs the listener until the server is shut
|
|
// down. A genuine listen failure (not the expected
|
|
// ErrServerClosed from a clean shutdown) requests process
|
|
// shutdown through fx with a non-zero exit code, so the failure
|
|
// is visible to any supervisor.
|
|
func (s *Server) listenAndServe() {
|
|
s.log.Info("http begin listen",
|
|
"listenaddr", s.httpServer.Addr,
|
|
"version", s.params.Globals.Version,
|
|
"buildarch", s.params.Globals.Buildarch,
|
|
)
|
|
|
|
err := s.httpServer.ListenAndServe()
|
|
if err == nil || errors.Is(err, http.ErrServerClosed) {
|
|
return
|
|
}
|
|
|
|
s.log.Error("listen error", "error", err)
|
|
|
|
shutdownErr := s.shutdowner.Shutdown(fx.ExitCode(1))
|
|
if shutdownErr != nil {
|
|
s.log.Error("request shutdown failed", "error", shutdownErr)
|
|
}
|
|
}
|