🐛 fix: emit all config-loading logs in correct JSON format from the start #16
@@ -48,8 +48,10 @@ func main() {
|
||||
log.Fatal().Err(err).Msg("Failed to load configuration")
|
||||
}
|
||||
|
||||
// Create readiness context to control readiness state
|
||||
readyCtx, readyCancel := context.WithCancel(context.Background())
|
||||
// Create readiness context to control readiness state.
|
||||
// CancelableContext exposes Cancel() so that Server.Run() can cancel
|
||||
// readiness at the start of graceful shutdown (before the propagation sleep).
|
||||
readyCtx, readyCancel := server.NewCancelableContext(context.Background())
|
||||
defer readyCancel()
|
||||
|
||||
// Create and run server
|
||||
@@ -57,4 +59,5 @@ func main() {
|
||||
if err := server.Run(); err != nil {
|
||||
log.Fatal().Err(err).Msg("Server failed")
|
||||
}
|
||||
log.Trace().Msg("Server exited")
|
||||
}
|
||||
|
||||
@@ -33,6 +33,28 @@ import (
|
||||
//go:embed docs/swagger.json
|
||||
var swaggerJSON embed.FS
|
||||
|
||||
// CancelableContext wraps a context.Context and exposes a Cancel() method so
|
||||
// that Server.Run() can cancel readiness during graceful shutdown via the type
|
||||
// assertion it already performs. Callers that don't need controlled cancellation
|
||||
// (tests, CLI) can pass a plain context.Background() — the assertion silently
|
||||
// fails and readiness is never explicitly cancelled, which is harmless.
|
||||
type CancelableContext struct {
|
||||
context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
// NewCancelableContext creates a CancelableContext whose Cancel() method will
|
||||
// be invoked by Server.Run() at the start of graceful shutdown, before the
|
||||
// 1-second readiness propagation window. The returned CancelFunc is a no-op
|
||||
// after Cancel() has been called, so it is safe to defer in main.
|
||||
func NewCancelableContext(parent context.Context) (*CancelableContext, context.CancelFunc) {
|
||||
ctx, cancel := context.WithCancel(parent)
|
||||
return &CancelableContext{Context: ctx, cancel: cancel}, cancel
|
||||
}
|
||||
|
||||
// Cancel satisfies the interface checked in Run() and cancels the context.
|
||||
func (c *CancelableContext) Cancel() { c.cancel() }
|
||||
|
||||
type Server struct {
|
||||
router *chi.Mux
|
||||
readyCtx context.Context
|
||||
|
||||
@@ -60,11 +60,39 @@ echo "Response: $GREET_NAME_RESPONSE"
|
||||
echo ""
|
||||
echo "Stopping server gracefully..."
|
||||
|
||||
# Test readiness during shutdown (in background)
|
||||
(curl -s http://localhost:8080/api/ready > /dev/null 2>&1 &)
|
||||
# Send SIGTERM once and probe /api/ready during the 1-second propagation window
|
||||
# the server holds open (pkg/server/server.go: time.Sleep(1s) after readiness
|
||||
# cancel). Previously the curl fired *before* the signal — it always saw "ready".
|
||||
# We also avoid calling "$SERVER_CMD stop" afterwards because that would send a
|
||||
# second SIGTERM: after signal.NotifyContext is done, the default handler kicks in
|
||||
# and the process terminates with a non-JSON "signal: terminated" on stderr.
|
||||
SERVER_PID=$(cat "$PID_FILE" 2>/dev/null || echo "")
|
||||
if [[ -z "$SERVER_PID" ]]; then
|
||||
echo -e "\033[0;31m❌ FAIL: PID file not found\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$SERVER_CMD stop
|
||||
sleep 3
|
||||
kill -TERM "$SERVER_PID"
|
||||
# Brief yield so the signal handler runs and CancelableContext.Cancel() fires
|
||||
sleep 0.2
|
||||
curl -s http://localhost:8080/api/ready > /dev/null 2>&1 || true
|
||||
|
||||
# Wait for the process to exit cleanly (up to 30s) without sending another signal
|
||||
echo "Waiting for server to exit..."
|
||||
for i in {1..30}; do
|
||||
if ! ps -p "$SERVER_PID" > /dev/null 2>&1; then
|
||||
echo "Server stopped successfully"
|
||||
rm -f "$PID_FILE"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ps -p "$SERVER_PID" > /dev/null 2>&1; then
|
||||
echo -e "\033[0;31m❌ FAIL: Server did not stop within 30s\033[0m"
|
||||
kill -9 "$SERVER_PID" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
sleep 0.5
|
||||
|
||||
echo ""
|
||||
echo "Analyzing server logs..."
|
||||
|
||||
Reference in New Issue
Block a user