- delete api/requests.http and ARCHITECTURE.md (coordinator content) - rewrite README.md and .env.example for the userservice - drop dead RunPeriodic (reaper machinery userservice has no use for) - fix .gitignore/.dockerignore/.golangci.yml module + artifact names - degeneralize stale copied comments that said "coordinator"
45 lines
1.2 KiB
Go
45 lines
1.2 KiB
Go
// Server: the HTTP listener, shut down cleanly on a signal.
|
|
package infra
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
const shutdownGrace = 15 * time.Second
|
|
|
|
// RunServer serves handler until ctx is cancelled, then drains in-flight requests.
|
|
func RunServer(ctx context.Context, log *slog.Logger, addr string, handler http.Handler) error {
|
|
srv := &http.Server{
|
|
Addr: addr,
|
|
Handler: handler,
|
|
ReadHeaderTimeout: 5 * time.Second,
|
|
}
|
|
|
|
// Buffered so this goroutine can exit even when nobody reads the channel
|
|
// (the ctx.Done branch below) — an unbuffered send would leak it forever.
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
log.Info("userservice listening", "addr", addr)
|
|
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
errCh <- err
|
|
}
|
|
}()
|
|
|
|
select {
|
|
case err := <-errCh:
|
|
return err
|
|
case <-ctx.Done():
|
|
log.Info("shutdown signal received")
|
|
}
|
|
|
|
// A fresh context: ctx is already cancelled, and reusing it would abort the
|
|
// very requests we are trying to let finish.
|
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownGrace)
|
|
defer cancel()
|
|
return srv.Shutdown(shutdownCtx)
|
|
}
|