Skip to content

Issue #958#976

Open
Suji2007hub wants to merge 2 commits into
Muneerali199:mainfrom
Suji2007hub:blackboxai/pr958-graceful-shutdown
Open

Issue #958#976
Suji2007hub wants to merge 2 commits into
Muneerali199:mainfrom
Suji2007hub:blackboxai/pr958-graceful-shutdown

Conversation

@Suji2007hub

@Suji2007hub Suji2007hub commented Jun 7, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Backend Go server with graceful shutdown support on signal termination
    • Health check and readiness endpoints
    • API echo endpoint for testing
  • Documentation

    • Backend server documentation with configuration, setup, and testing instructions
  • Tests

    • Graceful shutdown test suite covering request draining and timeout scenarios

@netlify

netlify Bot commented Jun 7, 2026

Copy link
Copy Markdown

👷 Deploy request for docmagic1 pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 58c7df9

@netlify

netlify Bot commented Jun 7, 2026

Copy link
Copy Markdown

👷 Deploy request for docmagic-muneer pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 58c7df9

@vercel

vercel Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

@Suji2007hub is attempting to deploy a commit to the muneerali199's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds graceful HTTP server shutdown functionality to the Go backend, including two reference server implementations with signal handling, configurable timeouts, comprehensive tests, and documentation. The primary implementation is in backend/go/cmd/server/main.go with full test coverage; a secondary implementation in backend/main.go is documented alongside it.

Changes

Go Backend Graceful Shutdown

Layer / File(s) Summary
Go Module Configuration
backend/go.mod
Module declaration and Go 1.21 toolchain version.
Primary Server with Graceful Shutdown
backend/go/cmd/server/main.go
HTTP server on :8080 with SIGINT/SIGTERM signal handling, 30-second graceful shutdown timeout, and three endpoints: /health, /ready (JSON status), and /api/echo (query-param-echoing with 100ms delay).
Graceful Shutdown Test Suite
backend/go/cmd/server/main_test.go
Two comprehensive tests: TestGracefulShutdownDrainsRequests validates in-flight requests complete within the shutdown timeout; TestGracefulShutdownTimeout confirms timeout errors and non-premature returns when handlers block past the deadline.
Alternative Server Implementation
backend/main.go
Secondary HTTP server with similar graceful shutdown pattern, serving /health and /api/test endpoints; included for documentation and reference.
Backend Documentation and Project Tracking
backend/README.md, TODO.md
README describes both server implementations, quick-start workflow, features (signal handling, logging, health checks), configuration notes, and testing guidance; TODO.md tracks completion of markdown cleanup and next steps.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

level:advanced, quality:clean, type:feature, type:devops, mentor:muneerali199

Poem

🐇 A graceful shutdown blooms so fair,
With signal catching in the air—
Two servers tested, docs so bright,
No hung connections in the night! 🌙✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is completely empty, missing all required template sections including summary, issue reference, type of change, changes made, dependencies, and testing information. Add a comprehensive description following the template, including issue #958, type of change, summary of changes made, testing details, and relevant checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is extremely vague and does not clearly convey the specific changes made, only referencing an issue number without describing the actual work. Replace with a descriptive title such as 'Add graceful shutdown support to Go backend servers' that clearly explains the main change.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (2)
backend/go/cmd/server/main_test.go (1)

139-143: ⚡ Quick win

Accepting nil from Serve may hide unexpected behavior.

Similar to the previous test, this accepts nil as a valid return value from srv.Serve(). According to Go's http.Server documentation, Serve always returns a non-nil error and should return http.ErrServerClosed after Shutdown is called.

♻️ Proposed fix to strictly check for ErrServerClosed
 	if serveErr := <-serverErr; serveErr != http.ErrServerClosed {
-		if serveErr != nil {
-			t.Fatalf("Serve error: %v", serveErr)
-		}
+		t.Fatalf("expected ErrServerClosed, got: %v", serveErr)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/go/cmd/server/main_test.go` around lines 139 - 143, The test
currently allows a nil value from srv.Serve by only failing when serveErr !=
http.ErrServerClosed && serveErr != nil; change the check to strictly require
serveErr == http.ErrServerClosed by replacing that conditional with a single
check that fails when serveErr != http.ErrServerClosed (e.g., using the
serverErr channel value), referencing srv.Serve and http.ErrServerClosed so the
test fails on any unexpected non-ErrServerClosed value instead of silently
accepting nil.
backend/go/cmd/server/main.go (1)

29-38: ⚡ Quick win

Potential race condition between server startup and signal handler setup.

If ListenAndServe fails immediately (e.g., port already in use), the goroutine will call os.Exit(1) at line 33, potentially before the signal handler is registered at line 38. While this might be acceptable behavior (the program should exit if the server can't start), it creates a race condition where the program might exit without the signal handler ever being installed.

Consider one of these approaches:

  1. Use a channel to signal successful server startup before setting up the signal handler
  2. Set up the signal handler before starting the server
  3. Document this race as intended behavior if it's acceptable
♻️ Proposed fix to synchronize startup
 func run() {
 	srv := &http.Server{
 		Addr:         ":8080",
 		Handler:      routes(),
 		ReadTimeout:  15 * time.Second,
 		WriteTimeout: 15 * time.Second,
 		IdleTimeout:  60 * time.Second,
 	}
 
+	// Set up signal handler before starting server to avoid race
+	sigChan := make(chan os.Signal, 1)
+	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
+
 	go func() {
 		log.Println("Server starting on :8080")
 		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
 			log.Printf("ListenAndServe error: %v", err)
 			os.Exit(1)
 		}
 	}()
 
-	sigChan := make(chan os.Signal, 1)
-	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
-
 	sig := <-sigChan
 	log.Printf("Signal: %v - initiating shutdown", sig)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/go/cmd/server/main.go` around lines 29 - 38, There is a race between
starting the server goroutine (srv.ListenAndServe) and registering the signal
handler (sigChan/signal.Notify); fix by installing the signal handler first and
synchronizing server startup failures via an error channel: create a
startupErrChan (chan error), call signal.Notify(sigChan, ...) before launching
the goroutine, have the goroutine send any ListenAndServe error into
startupErrChan (instead of calling os.Exit), then in main select on
startupErrChan and sigChan to handle immediate startup failures (call os.Exit(1)
on error) or graceful shutdown on signals; reference srv.ListenAndServe,
sigChan, signal.Notify and os.Exit in your changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/go.mod`:
- Line 3: The go directive in backend/go.mod currently sets an EOL Go version
("go 1.21"); update that directive to a supported release (e.g., "go 1.26" or
"go 1.26.4") to restore security updates, then run module housekeeping (e.g., go
mod tidy) and update any CI/build configs that pin Go (GitHub Actions,
Dockerfiles, build scripts) to the same new version so builds remain consistent;
locate the directive by opening backend/go.mod and change the line containing
"go 1.21".

In `@backend/go/cmd/server/main_test.go`:
- Around line 119-129: The test has a race: the goroutine calling client.Get may
not have actually sent the request before srv.Shutdown is invoked (symbols:
client.Get, srv.Shutdown, ln.Addr(), shutdownTimeout, shutdownStart), so
synchronize the request start before calling Shutdown; for example, create a
start signal (channel or sync.WaitGroup) that the goroutine closes/signals
immediately before performing client.Get (or that the server handler signals
when it begins handling), wait for that signal in the main test goroutine, then
call srv.Shutdown(ctx) and record shutdownStart — this guarantees the request is
in-flight when Shutdown is invoked.
- Around line 82-87: The current tests accept a nil error from the serverErr
channel which can mask unexpected Serve failures; update both checks (the server
err read in TestGracefulShutdown and the analogous check in
TestGracefulShutdownTimeout) to treat only http.ErrServerClosed as the expected
outcome and fail the test for any non-nil, non-http.ErrServerClosed error by
calling t.Fatalf with the actual error; locate the serverErr receive expressions
and replace the nil-accepting branch with a strict comparison against
http.ErrServerClosed and an explicit failure for other errors.

In `@backend/go/cmd/server/main.go`:
- Around line 72-83: The handler registered with mux.HandleFunc (the /api/echo
closure) directly interpolates the msg query param using fmt.Fprintf, causing
JSON injection; change it to build a proper Go value (e.g., a struct or map like
map[string]string{"echo": msg}) and write it with encoding/json
(json.NewEncoder(w).Encode or json.Marshal + w.Write) after setting
Content-Type, so the msg is correctly escaped/encoded; replace the fmt.Fprintf
call in the handler with the JSON encoder approach to eliminate injection.

In `@backend/main.go`:
- Around line 33-35: The signal channel created as sigChan is registered with
signal.Notify but never unregistered, risking a notifier leak during shutdown;
after the call to signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) add a
deferred call to signal.Stop(sigChan) so the runtime stops delivering signals to
that channel when shutdown begins (i.e. place defer signal.Stop(sigChan)
immediately after the signal.Notify invocation that references sigChan).

In `@backend/README.md`:
- Around line 23-25: The README.md contains fenced code blocks showing log
output that lack language identifiers (MD040); update each fenced block that
contains log lines like "2026/06/06 10:23:45 [INFO] Starting server on :8080"
and the subsequent shutdown log block ("[INFO] Received signal: interrupt..." /
"[INFO] Server shut down gracefully...") to include a language tag such as text
(i.e., replace ``` with ```text) so markdownlint passes and the code fences are
explicit.
- Around line 23-38: Update the README examples to match backend/main.go: change
the log example to the actual logger format used by the server (include the
date/time and “[INFO]” prefix as emitted by the code), correct the server
address to use the inline Addr ":8080" used in main.go, replace the placeholder
shutdown timeout in the docs with the actual shutdownTimeout constant value, and
fix the Windows shutdown command by removing the invalid "/SIGTERM" flag
(suggest using taskkill /PID <pid> /T or PowerShell Stop-Process -Id <pid> for
Windows); apply the same edits to the repeated section (lines 66-78).

---

Nitpick comments:
In `@backend/go/cmd/server/main_test.go`:
- Around line 139-143: The test currently allows a nil value from srv.Serve by
only failing when serveErr != http.ErrServerClosed && serveErr != nil; change
the check to strictly require serveErr == http.ErrServerClosed by replacing that
conditional with a single check that fails when serveErr != http.ErrServerClosed
(e.g., using the serverErr channel value), referencing srv.Serve and
http.ErrServerClosed so the test fails on any unexpected non-ErrServerClosed
value instead of silently accepting nil.

In `@backend/go/cmd/server/main.go`:
- Around line 29-38: There is a race between starting the server goroutine
(srv.ListenAndServe) and registering the signal handler (sigChan/signal.Notify);
fix by installing the signal handler first and synchronizing server startup
failures via an error channel: create a startupErrChan (chan error), call
signal.Notify(sigChan, ...) before launching the goroutine, have the goroutine
send any ListenAndServe error into startupErrChan (instead of calling os.Exit),
then in main select on startupErrChan and sigChan to handle immediate startup
failures (call os.Exit(1) on error) or graceful shutdown on signals; reference
srv.ListenAndServe, sigChan, signal.Notify and os.Exit in your changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f67b2ca-32a3-4ad7-9912-de0406a9a776

📥 Commits

Reviewing files that changed from the base of the PR and between c13823c and 58c7df9.

📒 Files selected for processing (6)
  • TODO.md
  • backend/README.md
  • backend/go.mod
  • backend/go/cmd/server/main.go
  • backend/go/cmd/server/main_test.go
  • backend/main.go

Comment thread backend/go.mod
Comment thread backend/go/cmd/server/main_test.go
Comment thread backend/go/cmd/server/main_test.go
Comment thread backend/go/cmd/server/main.go
Comment thread backend/main.go
Comment thread backend/README.md
Comment thread backend/README.md
Comment thread TODO.md
@Suji2007hub Suji2007hub closed this Jun 7, 2026
@Suji2007hub Suji2007hub reopened this Jun 7, 2026
@Muneerali199 Muneerali199 added type:docs PR type: docs level:beginner GSSoC difficulty: beginner gssoc:approved Required GSSoC approval label mentor:muneerali199 Reviewed by mentor muneerali199 labels Jun 10, 2026
@Muneerali199

Copy link
Copy Markdown
Owner

@Suji2007hub please rebase on latest main to resolve conflicts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved Required GSSoC approval label level:beginner GSSoC difficulty: beginner mentor:muneerali199 Reviewed by mentor muneerali199 type:docs PR type: docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants