🐛 fix: wire up readiness cancellation and stabilise graceful shutdown test
Three related issues fixed together:
1. Readiness context was never cancelled during shutdown
server.Run() had a type assertion for a Cancel() method that no standard
context.Context implements, so readiness stayed "ready" through the entire
shutdown window. Added CancelableContext to pkg/server — a thin wrapper that
exposes Cancel() — and switched cmd/server/main.go to use it. Test servers
and CLI continue passing context.Background() unchanged.
2. "Server exited" log was never emitted
The test script expected it; main.go had no log after server.Run() returned.
Added log.Trace().Msg("Server exited") after the Run() call.
3. Double-SIGTERM caused non-JSON "signal: terminated" in server.log
test-graceful-shutdown.sh sent SIGTERM, then called $SERVER_CMD stop which
sent a second SIGTERM. After signal.NotifyContext is cancelled, the second
signal hits the default handler and Go prints "signal: terminated" to stderr,
breaking the all-JSON-lines assertion. Fixed by waiting for the PID to exit
ourselves instead of re-invoking the stop script.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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