-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🔥 feat: Improve and Optimize ShutdownWithContext Func #3162
base: main
Are you sure you want to change the base?
🔥 feat: Improve and Optimize ShutdownWithContext Func #3162
Conversation
- Reorder mutex lock acquisition to the start of the function - Early return if server is not running - Use defer for executing shutdown hooks - Simplify nil check for hooks - Remove TODO comment This commit improves the readability, robustness, and execution order of the shutdown process. It ensures consistent state throughout the shutdown and guarantees hook execution even in error cases.
- Add shutdown hook verification - Implement better synchronization with channels - Improve error handling and assertions - Adjust timeouts for more consistent results - Add server state check after shutdown attempt - Include comments explaining expected behavior This commit improves the comprehensiveness and reliability of the ShutdownWithContext test, ensuring proper verification of shutdown hooks, timeout behavior, and server state during long-running requests.
Thanks for opening this pull request! 🎉 Please check out our contributing guidelines. If you need help or want to chat with us, join us on Discord https://gofiber.io/discord |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3162 +/- ##
==========================================
+ Coverage 84.08% 84.11% +0.02%
==========================================
Files 116 116
Lines 11551 11558 +7
==========================================
+ Hits 9713 9722 +9
+ Misses 1405 1404 -1
+ Partials 433 432 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
app_test.go
Outdated
}() | ||
|
||
<-clientDone | ||
time.Sleep(100 * time.Millisecond) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need a sleep here? i think it's arbitrary since we already wait for clientDone channel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need a sleep here? i think it's arbitrary since we already wait for clientDone channel
This sleep is to ensure that our server has started processing the request. Although we have confirmed that the client has sent the request through <-clientDone, this means that the request has been sent to the server's listening port, and there is no guarantee that the server's processing coroutine has been sent. Start processing the request, so I think sleep 100 * Millisecond is required here as well.
WalkthroughThe changes enhance the Fiber web framework by introducing a new method Changes
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🧰 Additional context used🪛 golangci-lint (1.62.2)listen_test.go75-75: Function (contextcheck) 🪛 GitHub Check: lintlisten_test.go[failure] 75-75: 🪛 GitHub Actions: golangci-lintlisten_test.go[error] 75-75: Function ⏰ Context from checks skipped due to timeout of 90000ms (3)
🔇 Additional comments (2)
✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
…e/improve-shutdown-with-context
…ub.com:JIeJaitt/fiber into jiejaitt-feature/improve-shutdown-with-context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (1)
docs/api/fiber.md (1)
208-208
: Approve with minor suggestions for improvementThe added description for
ShutdownWithContext
is informative and aligns well with the PR objectives. It provides important details about the method's behavior, especially regarding the execution of shutdown hooks. To enhance clarity and readability, consider the following suggestions:
- Add a comma after "including" for better sentence structure.
- Split the long sentence into two for improved readability.
Here's a suggested revision:
- ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded.Shutdown hooks will still be executed, even if an error occurs during the shutdown process, as they are deferred to ensure cleanup happens regardless of errors. + ShutdownWithContext shuts down the server, including by force if the context's deadline is exceeded. Shutdown hooks will still be executed, even if an error occurs during the shutdown process, as they are deferred to ensure cleanup happens regardless of errors.🧰 Tools
🪛 LanguageTool
[uncategorized] ~208-~208: Possible missing comma found.
Context: ...es. ShutdownWithContext shuts down the server including by force if the context's dea...(AI_HYDRA_LEO_MISSING_COMMA)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- app.go (1 hunks)
- app_test.go (1 hunks)
- docs/api/fiber.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/api/fiber.md
[uncategorized] ~208-~208: Possible missing comma found.
Context: ...es. ShutdownWithContext shuts down the server including by force if the context's dea...(AI_HYDRA_LEO_MISSING_COMMA)
🔇 Additional comments (1)
app.go (1)
846-855
: Improved shutdown process with deferred hook executionThe changes to the
ShutdownWithContext
method enhance the shutdown process in several ways:
- Thread-safety is ensured by acquiring a mutex lock at the beginning of the method.
- A nil check for the server prevents potential panics if the server hasn't been initialized.
- The deferral of
executeOnShutdownHooks
guarantees that shutdown hooks are executed even if an error occurs during the shutdown process.These improvements contribute to a more robust and reliable shutdown mechanism.
app_test.go
Outdated
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | ||
defer cancel() | ||
shutdownErr <- app.ShutdownWithContext(ctx) | ||
}() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure Proper Context Cancellation
The context created with context.WithTimeout
should have its cancellation function deferred immediately to prevent potential resource leaks, even if an error occurs before the defer statement is reached.
Suggested Improvement
Move the defer cancel()
directly after context creation.
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
shutdownErr <- app.ShutdownWithContext(ctx)
- defer cancel()
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | |
defer cancel() | |
shutdownErr <- app.ShutdownWithContext(ctx) | |
}() | |
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | |
defer cancel() | |
shutdownErr <- app.ShutdownWithContext(ctx) | |
}() |
app_test.go
Outdated
case err := <-serverErr: | ||
assert.NoError(t, err, "Server should have shut down without error") | ||
default: | ||
// Server is still running, which is expected as the long-running request prevented full shutdown | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid Skipping Server Error Handling
Using a default
case in the select
statement may cause the test to proceed without waiting for the server to shut down, potentially leading to flaky tests. It's important to handle the server error explicitly.
Suggested Fix: Remove the default
Case
This ensures the test waits for serverErr
to receive an error or completes the shutdown process.
select {
case err := <-serverErr:
assert.NoError(t, err, "Server should have shut down without error")
- default:
- // Server is still running, which is expected as the long-running request prevented full shutdown
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
case err := <-serverErr: | |
assert.NoError(t, err, "Server should have shut down without error") | |
default: | |
// Server is still running, which is expected as the long-running request prevented full shutdown | |
} | |
case err := <-serverErr: | |
assert.NoError(t, err, "Server should have shut down without error") |
app_test.go
Outdated
shutdownHookCalled := false | ||
app.Hooks().OnShutdown(func() error { | ||
shutdownHookCalled = true | ||
return nil | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible Data Race on shutdownHookCalled
Variable
The shutdownHookCalled
boolean is accessed by multiple goroutines without proper synchronization, which could lead to a data race. In Go, variables shared between goroutines should be protected using synchronization mechanisms like channels, mutexes, or atomic operations.
Suggested Fix: Use an Atomic Variable
Replace shutdownHookCalled
with an int32
and use atomic.StoreInt32
and atomic.LoadInt32
for thread-safe operations.
+import "sync/atomic"
- shutdownHookCalled := false
+ var shutdownHookCalled int32
app.Hooks().OnShutdown(func() error {
- shutdownHookCalled = true
+ atomic.StoreInt32(&shutdownHookCalled, 1)
return nil
})
// ...
- assert.True(t, shutdownHookCalled, "Shutdown hook was not called")
+ assert.Equal(t, int32(1), atomic.LoadInt32(&shutdownHookCalled), "Shutdown hook was not called")
Committable suggestion was skipped due to low confidence.
@@ -205,7 +205,7 @@ Shutdown gracefully shuts down the server without interrupting any active connec | |||
|
|||
ShutdownWithTimeout will forcefully close any active connections after the timeout expires. | |||
|
|||
ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded. | |||
ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded. Shutdown hooks will still be executed, even if an error occurs during the shutdown process, as they are deferred to ensure cleanup happens regardless of errors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this behavior. I think we should only execute them during successful shutdown. Maybe we can OnShutdownError hook. What do you think @gaby @ReneWerner87
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure either. Also not sure about the defer of the hook
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to add Post Pre hook
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The add Post Pre hook is a good idea, but how do I tell which hooks are pre closed and which are post closed? @efectn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add new hook called PostShutdown, PreShutdown and replace the old one with them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sound good, @JIeJaitt can you do the suggested change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means making a change below the type Hooks struct
to add these two fields that mean PreShutdownHandler
and PostShutdownHandler
respectively , if I understand it correctly I'll try to implement it @ReneWerner87 @efectn @gaby
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means making a change below the
type Hooks struct
to add these two fields that meanPreShutdownHandler
andPostShutdownHandler
respectively , if I understand it correctly I'll try to implement it @ReneWerner87 @efectn @gaby
Yes it is. You can also add err parameter to PostShutdown hook, so that we can also get rid of OnShutdownError, OnShutdownSuccess properties of ListenerConfig.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means making a change below the
type Hooks struct
to add these two fields that meanPreShutdownHandler
andPostShutdownHandler
respectively , if I understand it correctly I'll try to implement it @ReneWerner87 @efectn @gabyYes it is. You can also add err parameter to PostShutdown hook, so that we can also get rid of OnShutdownError, OnShutdownSuccess properties of ListenerConfig.
OK, I will press on with this idea to realize it again in my free time, by the way what is the v3 deadline as I am busy with my final exams these days.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means making a change below the
type Hooks struct
to add these two fields that meanPreShutdownHandler
andPostShutdownHandler
respectively , if I understand it correctly I'll try to implement it @ReneWerner87 @efectn @gabyYes it is. You can also add err parameter to PostShutdown hook, so that we can also get rid of OnShutdownError, OnShutdownSuccess properties of ListenerConfig.
OK, I will press on with this idea to realize it again in my free time, by the way what is the v3 deadline as I am busy with my final exams these days.
We want to release v3 rc1 in the beginning of January. If you can't look at the PR this week, i can also look no problem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
app_test.go (1)
913-918
: Consider removing commented codeThe commented
default
case on line 917 should be removed as it's no longer needed.- // default: - // Server is still running, which is expected as the long-running request prevented full shutdown
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
app.go
(1 hunks)app_test.go
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app.go
🧰 Additional context used
📓 Learnings (1)
app_test.go (1)
Learnt from: efectn
PR: gofiber/fiber#3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.
🔇 Additional comments (6)
app_test.go (6)
24-24
: LGTM: Import atomic package for thread-safe operations
The addition of the sync/atomic
import is appropriate for implementing thread-safe operations in the test.
865-869
: LGTM: Thread-safe shutdown hook tracking
The use of atomic.Int32
for tracking the shutdown hook call is a thread-safe approach, ensuring accurate state tracking in concurrent scenarios.
878-881
: LGTM: Proper error handling with buffered channel
Using a buffered channel for server errors prevents potential goroutine leaks and ensures errors are properly captured.
885-891
: LGTM: Proper client request setup with synchronization
The client request is properly set up with error handling and synchronization using a channel to signal completion.
894-896
: Consider removing the sleep after clientDone
The sleep after the clientDone
channel might be unnecessary since we already have synchronization through the channel.
Based on the past review comments and learnings, the clientDone
channel is sufficient for synchronization, making the sleep redundant.
898-911
: LGTM: Robust shutdown handling with timeout
The shutdown handling is well-implemented with:
- Proper context timeout
- Deferred context cancellation
- Clear error assertions for timeout scenarios
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (3)
hooks.go (2)
105-111
: Remove commented-out codeThe TODO comment and commented-out
OnShutdown
code should be removed since it's being replaced by the new pre/post shutdown hooks.-// TODO:To be deleted, replaced by OnPreShutdown and OnPostShutdown -// OnShutdown is a hook to execute user functions after Shutdown. -// func (h *Hooks) OnShutdown(handler ...OnShutdownHandler) { -// h.app.mutex.Lock() -// h.onShutdown = append(h.onShutdown, handler...) -// h.app.mutex.Unlock() -// }
223-229
: Consider adding error return values to hook execution methodsThe hook execution methods currently log errors but don't return them. Consider returning an error to allow callers to handle failures appropriately.
-func (h *Hooks) executeOnPreShutdownHooks() { +func (h *Hooks) executeOnPreShutdownHooks() error { + var lastErr error for _, v := range h.onPreShutdown { if err := v(); err != nil { log.Errorf("failed to call pre shutdown hook: %v", err) + lastErr = err } } + return lastErr } -func (h *Hooks) executeOnPostShutdownHooks(err error) { +func (h *Hooks) executeOnPostShutdownHooks(err error) error { + var lastErr error for _, v := range h.onPostShutdown { if err := v(err); err != nil { log.Errorf("failed to call post shutdown hook: %v", err) + lastErr = err } } + return lastErr }Also applies to: 231-235
app_test.go (1)
918-919
: Remove commented-out codeThe commented-out default case should be removed as it's no longer needed.
- // default: - // Server is still running, which is expected as the long-running request prevented full shutdown
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (4)
app.go
(1 hunks)app_test.go
(2 hunks)hooks.go
(5 hunks)hooks_test.go
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- hooks_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
- app.go
🧰 Additional context used
📓 Learnings (1)
app_test.go (1)
Learnt from: efectn
PR: gofiber/fiber#3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.
🔇 Additional comments (4)
hooks.go (2)
14-16
: LGTM: Clear type definitions for shutdown hooks
The new pre and post shutdown handler types are well-defined and follow a logical separation of concerns.
32-34
: LGTM: Consistent hook storage in Hooks struct
The hook storage fields follow the same pattern as other hooks in the struct.
app_test.go (2)
879-882
: LGTM: Proper error handling for server shutdown
The serverErr channel is correctly used to capture and verify server errors.
895-897
: 🛠️ Refactor suggestion
Remove redundant sleep
Based on the learnings from efectn, the time.Sleep
is redundant since we already wait for the clientDone
channel.
<-clientDone
-// Sleep to ensure the server has started processing the request
-time.Sleep(100 * time.Millisecond)
Likely invalid or redundant comment.
hooks.go
Outdated
func (h *Hooks) executeOnPostShutdownHooks(err error) { | ||
for _, v := range h.onPostShutdown { | ||
if err := v(err); err != nil { | ||
log.Errorf("failed to call pre shutdown hook: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix error message in log
The error message incorrectly states "pre shutdown hook" when it should be "post shutdown hook".
- log.Errorf("failed to call pre shutdown hook: %v", err)
+ log.Errorf("failed to call post shutdown hook: %v", err)
Also applies to: 234-234
app_test.go
Outdated
var shutdownHookCalled atomic.Int32 | ||
// TODO: add test | ||
// app.Hooks().OnShutdown(func() error { | ||
// shutdownHookCalled.Store(1) | ||
// return nil | ||
// }) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Uncomment and update shutdown hook test
The TODO comment and commented-out shutdown hook test should be uncommented and updated to use the new pre/post shutdown hooks.
var shutdownHookCalled atomic.Int32
-// TODO: add test
-// app.Hooks().OnShutdown(func() error {
-// shutdownHookCalled.Store(1)
-// return nil
-// })
+app.Hooks().OnPreShutdown(func() error {
+ shutdownHookCalled.Store(1)
+ return nil
+})
Committable suggestion skipped: line range outside the PR's diff.
…e/improve-shutdown-with-context
@efectn @ReneWerner87 @gaby I have completed the general revision, now can review my revision ideas, the rest of the lint problem and the content of the new document to add, and so on the big brothers review after I write, to prevent me from writing problems need to repeatedly modify the document! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (10)
hooks_test.go (3)
238-238
: Rename Unused Parametererr
to Enhance ReadabilityThe parameter
err
in the closure is not used, which may cause confusion. Renaming it to_
clarifies that it is intentionally unused.Apply this diff:
- app.Hooks().OnPostShutdown(func(err error) error { + app.Hooks().OnPostShutdown(func(_ error) error { execution = append(execution, 1) return nil })🧰 Tools
🪛 GitHub Check: lint
[failure] 238-238:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)🪛 golangci-lint (1.62.2)
[warning] 238-238: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
243-243
: Rename Unused Parametererr
to Enhance ReadabilityThe parameter
err
in the closure is not used. Consider renaming it to_
to indicate that it is intentionally unused.Apply this diff:
- app.Hooks().OnPostShutdown(func(err error) error { + app.Hooks().OnPostShutdown(func(_ error) error { execution = append(execution, 2) return nil })🧰 Tools
🪛 GitHub Check: lint
[failure] 243-243:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)🪛 golangci-lint (1.62.2)
[warning] 243-243: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
263-263
: Rename Unused Parametererr
in ClosureThe parameter
err
is not used within this closure. Renaming it to_
will make it clear that the error parameter is intentionally unused.Apply this diff:
- app.Hooks().OnPostShutdown(func(err error) error { + app.Hooks().OnPostShutdown(func(_ error) error { return hookErr })🧰 Tools
🪛 GitHub Check: lint
[failure] 263-263:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)🪛 golangci-lint (1.62.2)
[warning] 263-263: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
listen_test.go (6)
50-50
: Addt.Helper()
to Helper FunctionThe function
testGracefulShutdown
is a test helper function. Addingt.Helper()
at the beginning of the function improves test diagnostics by marking it as a helper.Apply this diff:
func testGracefulShutdown(t *testing.T, shutdownTimeout time.Duration) { + t.Helper() var mu sync.Mutex var shutdown bool
🧰 Tools
🪛 GitHub Check: lint
[failure] 50-50:
test helper function should start from t.Helper() (thelper)🪛 golangci-lint (1.62.2)
50-50: test helper function should start from t.Helper()
(thelper)
62-62
: Rename Unused Parametererr
in ClosureThe parameter
err
in the closure is not used. Renaming it to_
clarifies that it's intentionally unused.Apply this diff:
-app.hooks.OnPostShutdown(func(err error) error { +app.hooks.OnPostShutdown(func(_ error) error { mu.Lock() defer mu.Unlock() shutdown = true return nil })🧰 Tools
🪛 GitHub Check: lint
[failure] 62-62:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)🪛 golangci-lint (1.62.2)
[warning] 62-62: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
83-83
: Check Error Return Value ofconn.Close()
The error returned by
conn.Close()
is not checked. Failing to handle potential errors might lead to resource leaks or unnoticed issues.Apply this diff:
conn, err := ln.Dial() if err == nil { - conn.Close() + err := conn.Close() + if err != nil { + t.Errorf("Error closing connection: %v", err) + } return true }🧰 Tools
🪛 GitHub Check: lint
[failure] 83-83:
Error return value ofconn.Close
is not checked (errcheck)🪛 golangci-lint (1.62.2)
83-83: Error return value of
conn.Close
is not checked(errcheck)
120-120
: Avoid Unnecessary Copy of Loop VariableIn Go 1.22 and later, it is unnecessary to create a new variable
tc
inside the loop. The loop variable is no longer reused across iterations, making the copy redundant.Apply this diff:
for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { time.Sleep(tc.waitTime)
🧰 Tools
🪛 golangci-lint (1.62.2)
120-120: The copy of the 'for' variable "tc" can be deleted (Go 1.22+)
(copyloopvar)
134-134
: Userequire.NoError
Instead ofassert.NoError
In test code, using
require.NoError
is preferred overassert.NoError
when the test cannot proceed if there's an error. It fails the test immediately, preventing further assertions on invalid data.Apply this diff:
- assert.NoError(t, err) + require.NoError(t, err)🧰 Tools
🪛 golangci-lint (1.62.2)
134-134: require-error: for error assertions use require
(testifylint)
145-145
: Userequire.NoError
Instead ofassert.NoError
To ensure the test fails immediately if there is an error, use
require.NoError
instead ofassert.NoError
.Apply this diff:
- assert.NoError(t, <-errs) + require.NoError(t, <-errs)🧰 Tools
🪛 golangci-lint (1.62.2)
145-145: require-error: for error assertions use require
(testifylint)
listen.go (1)
485-489
: Architectural improvement: Centralized shutdown notification via hooksThe change from direct callback functions to using the hooks system is a good architectural improvement. This centralization makes the shutdown process more maintainable and consistent.
Consider documenting the hook execution order in the package documentation to help users understand when their hooks will be called during shutdown.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 485-485: listen.go#L485
Added line #L485 was not covered by tests
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (6)
app.go
(1 hunks)app_test.go
(2 hunks)hooks.go
(5 hunks)hooks_test.go
(1 hunks)listen.go
(1 hunks)listen_test.go
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app.go
🧰 Additional context used
📓 Learnings (1)
app_test.go (1)
Learnt from: efectn
PR: gofiber/fiber#3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.
🪛 GitHub Check: codecov/patch
listen.go
[warning] 485-485: listen.go#L485
Added line #L485 was not covered by tests
hooks.go
[warning] 207-208: hooks.go#L207-L208
Added lines #L207 - L208 were not covered by tests
🪛 GitHub Check: lint
hooks_test.go
[failure] 217-217:
Error return value of app.Listen
is not checked (errcheck)
[failure] 228-228:
comparing with != will fail on wrapped errors. Use errors.Is to check for a specific error (errorlint)
[failure] 238-238:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)
[failure] 243-243:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)
[failure] 259-259:
unused-parameter: parameter 't' seems to be unused, consider removing or renaming it as _ (revive)
[failure] 263-263:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)
listen_test.go
[failure] 50-50:
test helper function should start from t.Helper() (thelper)
[failure] 62-62:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)
[failure] 73-73:
Function Listener
should pass the context parameter (contextcheck)
[failure] 83-83:
Error return value of conn.Close
is not checked (errcheck)
🪛 golangci-lint (1.62.2)
hooks_test.go
217-217: Error return value of app.Listen
is not checked
(errcheck)
228-228: comparing with != will fail on wrapped errors. Use errors.Is to check for a specific error
(errorlint)
[warning] 238-238: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
[warning] 243-243: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
[warning] 259-259: unused-parameter: parameter 't' seems to be unused, consider removing or renaming it as _
(revive)
[warning] 263-263: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
listen_test.go
50-50: test helper function should start from t.Helper()
(thelper)
[warning] 62-62: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
73-73: Function Listener
should pass the context parameter
(contextcheck)
83-83: Error return value of conn.Close
is not checked
(errcheck)
93-93: fieldalignment: struct with 64 pointer bytes could be 40
(govet)
120-120: The copy of the 'for' variable "tc" can be deleted (Go 1.22+)
(copyloopvar)
134-134: require-error: for error assertions use require
(testifylint)
145-145: require-error: for error assertions use require
(testifylint)
🔇 Additional comments (4)
app_test.go (1)
895-897
: Consider Removing Unnecessary Sleep to Improve Test Reliability
Using time.Sleep(100 * time.Millisecond)
after receiving clientDone
might lead to flaky tests or unnecessary delays. Since the clientDone
channel ensures that the client has sent the request, consider implementing a synchronization mechanism to confirm that the server has started processing the request instead of relying on time.Sleep
.
hooks.go (1)
207-208
: 🛠️ Refactor suggestion
Increase Test Coverage for Error Handling in executeOnPreShutdownHooks
The error handling code within executeOnPreShutdownHooks
is not currently covered by tests. To ensure that errors returned by pre-shutdown hooks are properly handled and logged, consider adding test cases that include pre-shutdown hooks which return errors. This will improve the robustness and reliability of the shutdown process.
Would you like assistance in generating the necessary tests to cover this error handling code?
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 207-208: hooks.go#L207-L208
Added lines #L207 - L208 were not covered by tests
listen.go (2)
485-489
: Verify hook execution order
The hooks system needs to guarantee consistent execution order during shutdown.
Let's verify the hook execution implementation:
✅ Verification successful
Hook execution order is properly maintained
The implementation guarantees consistent execution order during shutdown:
- Hooks are stored in a slice (
onPostShutdown
) that maintains insertion order - Registration is thread-safe using app-level mutex lock/unlock
- Hooks are executed sequentially in the order they were registered
- Error handling is properly implemented without breaking execution order
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check hooks implementation
ast-grep --pattern 'func (h *Hooks) executeOnPostShutdownHooks($_) {
$$$
}'
# Check for potential race conditions in hooks execution
rg -A 5 "sync\.Mutex.*executeOnPostShutdownHooks"
Length of output: 418
Script:
#!/bin/bash
# Check how hooks are registered and stored
ast-grep --pattern 'type Hooks struct {
$$$
}'
# Check hook registration methods
ast-grep --pattern 'func (h *Hooks) OnPostShutdown($_) {
$$$
}'
# Look for hook registration calls
rg -A 2 "OnPostShutdown"
Length of output: 3150
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 485-485: listen.go#L485
Added line #L485 was not covered by tests
485-485
: Add test coverage for error path
The static analysis indicates that line 485 (error path) lacks test coverage.
Let's verify the test coverage and existing tests:
Would you like me to help create a test case that covers the error path during shutdown?
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 485-485: listen.go#L485
Added line #L485 was not covered by tests
hooks_test.go
Outdated
t.Fatal("hook was not called") | ||
} | ||
|
||
if receivedErr != expectedErr { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use errors.Is
for Error Comparison
Comparing errors using !=
may fail when errors are wrapped. To accurately check for specific errors, use errors.Is
instead.
Apply this diff to improve error comparison:
- if receivedErr != expectedErr {
+ if !errors.Is(receivedErr, expectedErr) {
t.Fatalf("hook received wrong error: want %v, got %v", expectedErr, receivedErr)
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if receivedErr != expectedErr { | |
if !errors.Is(receivedErr, expectedErr) { |
🧰 Tools
🪛 GitHub Check: lint
[failure] 228-228:
comparing with != will fail on wrapped errors. Use errors.Is to check for a specific error (errorlint)
🪛 golangci-lint (1.62.2)
228-228: comparing with != will fail on wrapped errors. Use errors.Is to check for a specific error
(errorlint)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use require methods instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@efectn, you're right, using the require
methods simplifies the test assertions. You can modify the test code to:
require.ErrorIs(t, receivedErr, expectedErr)
or
require.Equal(t, expectedErr, receivedErr)
This leverages the testify package's assertion functions for cleaner and more expressive tests.
✏️ Learnings added
Learnt from: efectn
PR: gofiber/fiber#3162
File: hooks_test.go:228-228
Timestamp: 2024-12-13T08:14:22.698Z
Learning: In Go test files, prefer using the `require` methods from the `testify` package for assertions instead of manual comparisons and calls to `t.Fatal` or `t.Fatalf`.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
hooks_test.go
Outdated
}) | ||
|
||
go func() { | ||
_ = app.Listen(":0") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check Error Return Value of app.Listen
The error returned by app.Listen(":0")
is not checked. Ignoring errors can lead to unexpected behaviors or missed errors during testing. Please handle the error appropriately to ensure that any issues during the listening process are captured.
Apply this diff to handle the error:
- _ = app.Listen(":0")
+ err := app.Listen(":0")
+ require.NoError(t, err, "app.Listen failed")
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
_ = app.Listen(":0") | |
err := app.Listen(":0") | |
require.NoError(t, err, "app.Listen failed") |
🧰 Tools
🪛 GitHub Check: lint
[failure] 217-217:
Error return value of app.Listen
is not checked (errcheck)
🪛 golangci-lint (1.62.2)
217-217: Error return value of app.Listen
is not checked
(errcheck)
@@ -900,16 +900,18 @@ func (app *App) ShutdownWithTimeout(timeout time.Duration) error { | |||
// | |||
// ShutdownWithContext does not close keepalive connections so its recommended to set ReadTimeout to something else than 0. | |||
func (app *App) ShutdownWithContext(ctx context.Context) error { | |||
if app.hooks != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we can define executeOnPostShutdownHooks hook with defer as well as PreShutdownHook
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we can define executeOnPostShutdownHooks hook with defer as well as PreShutdownHook
Is that what you mean?I think PreShutdownHook
and PostShutdownHook
set outside the function and then executed at ShutdownWithContext
func (app *App) ShutdownWithContext(ctx context.Context) error {
app.mutex.Lock()
defer app.mutex.Unlock()
if app.server == nil {
return ErrNotRunning
}
// Execute the Shutdown hook
if app.hooks != nil {
app.hooks.executeOnPreShutdownHooks()
}
defer app.hooks.executeOnPostShutdownHooks(nil)
return app.server.ShutdownWithContext(ctx)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we can define executeOnPostShutdownHooks hook with defer as well as PreShutdownHook
Is that what you mean?I think
PreShutdownHook
andPostShutdownHook
set outside the function and then executed atShutdownWithContext
func (app *App) ShutdownWithContext(ctx context.Context) error { app.mutex.Lock() defer app.mutex.Unlock() if app.server == nil { return ErrNotRunning } // Execute the Shutdown hook if app.hooks != nil { app.hooks.executeOnPreShutdownHooks() } defer app.hooks.executeOnPostShutdownHooks(nil) return app.server.ShutdownWithContext(ctx) }
You can do it like:
func (app *App) ShutdownWithContext(ctx context.Context) error {
app.mutex.Lock()
defer app.mutex.Unlock()
var err error
if app.server == nil {
return ErrNotRunning
}
// Execute the Shutdown hook
app.hooks.executeOnPreShutdownHooks()
defer app.hooks.executeOnPostShutdownHooks(err)
err = app.server.ShutdownWithContext(ctx)
return err
}
So that, we won't need to add another additional check to listen.go and this is going to work even if you use app.Shutdown() separately. However, this hook wouldn't work if app.Listen() hadn't been started in another goroutine. Maybe we can also add a note to indicate it -> https://github.com/valyala/fasthttp/blob/master/server.go#L1830
@JIeJaitt can you update the code with the last ideas |
…/improve-shutdown-with-context
…ooks Instead of OnShutdownSuccess and OnShutdownError
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (6)
docs/api/fiber.md (1)
233-233
: Improve documentation clarity and fix grammar.The sentence structure could be improved for better readability and comprehension.
Apply this diff to enhance clarity and fix grammar:
-ShutdownWithContext shuts down the server including by force if the context's deadline is exceeded. Shutdown hooks will still be executed, even if an error occurs during the shutdown process, as they are deferred to ensure cleanup happens regardless of errors. +ShutdownWithContext shuts down the server, including by force, if the context's deadline is exceeded. Shutdown hooks will still be executed, even if an error occurs during the shutdown process, as they are deferred to ensure cleanup happens regardless of errors.🧰 Tools
🪛 LanguageTool
[uncategorized] ~233-~233: Possible missing comma found.
Context: ...es. ShutdownWithContext shuts down the server including by force if the context's dea...(AI_HYDRA_LEO_MISSING_COMMA)
app_test.go (2)
942-942
: Replace sleep with proper synchronization.Using
time.Sleep
for synchronization can make tests flaky. Consider using a channel orsync.WaitGroup
to properly synchronize the server startup.Here's how you could improve it:
+ serverReady := make(chan struct{}) go func() { + defer close(serverReady) _ = app.Listener(ln) }() - time.Sleep(100 * time.Millisecond) + <-serverReady
930-935
: Improve hook error handling.The
err
parameter in the post-shutdown hook is unused. Either use it to verify the shutdown error or rename it to_
to indicate it's intentionally ignored.Apply this diff:
-app.Hooks().OnPostShutdown(func(err error) error { +app.Hooks().OnPostShutdown(func(_ error) error { hookMutex.Lock() hookOrder = append(hookOrder, "post") hookMutex.Unlock() return nil })🧰 Tools
🪛 golangci-lint (1.62.2)
[warning] 930-930: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
🪛 GitHub Check: lint
[failure] 930-930:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)listen_test.go (3)
62-67
: Consider using the error parameter or rename it to _.The error parameter in the OnPostShutdown hook is unused.
-app.hooks.OnPostShutdown(func(err error) error { +app.hooks.OnPostShutdown(func(_ error) error {🧰 Tools
🪛 golangci-lint (1.62.2)
[warning] 62-62: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
83-83
: Check error from conn.Close.The error from
conn.Close()
should be checked.-conn.Close() +if err := conn.Close(); err != nil { + t.Logf("error closing connection: %v", err) +}🧰 Tools
🪛 golangci-lint (1.62.2)
83-83: Error return value of
conn.Close
is not checked(errcheck)
134-134
: Use require instead of assert for error checks.For error assertions, use
require
instead ofassert
to ensure the test fails immediately if the assertion fails.-assert.NoError(t, err) +require.NoError(t, err) -assert.NoError(t, <-errs) +require.NoError(t, <-errs)Also applies to: 145-145
🧰 Tools
🪛 golangci-lint (1.62.2)
134-134: require-error: for error assertions use require
(testifylint)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app.go
(2 hunks)app_test.go
(2 hunks)docs/api/fiber.md
(1 hunks)listen.go
(1 hunks)listen_test.go
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app.go
🧰 Additional context used
🧠 Learnings (1)
app_test.go (1)
Learnt from: efectn
PR: gofiber/fiber#3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.
🪛 GitHub Check: codecov/patch
listen.go
[warning] 500-500: listen.go#L500
Added line #L500 was not covered by tests
🪛 golangci-lint (1.62.2)
app_test.go
897-897: Error return value of app.Listener
is not checked
(errcheck)
[warning] 930-930: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
939-939: Error return value of app.Listener
is not checked
(errcheck)
961-961: Error return value of app.Listener
is not checked
(errcheck)
968-968: Error return value of ln.Dial
is not checked
(errcheck)
969-969: Error return value of conn.Write
is not checked
(errcheck)
listen_test.go
50-50: test helper function should start from t.Helper()
(thelper)
[warning] 62-62: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
73-73: Function Listener
should pass the context parameter
(contextcheck)
83-83: Error return value of conn.Close
is not checked
(errcheck)
93-93: fieldalignment: struct with 64 pointer bytes could be 40
(govet)
120-120: The copy of the 'for' variable "tc" can be deleted (Go 1.22+)
(copyloopvar)
134-134: require-error: for error assertions use require
(testifylint)
145-145: require-error: for error assertions use require
(testifylint)
🪛 GitHub Check: lint
app_test.go
[failure] 897-897:
Error return value of app.Listener
is not checked (errcheck)
[failure] 930-930:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)
[failure] 939-939:
Error return value of app.Listener
is not checked (errcheck)
[failure] 961-961:
Error return value of app.Listener
is not checked (errcheck)
[failure] 968-968:
Error return value of ln.Dial
is not checked (errcheck)
[failure] 969-969:
Error return value of conn.Write
is not checked (errcheck)
🪛 GitHub Actions: golangci-lint
app_test.go
[error] 897-897: Error return value of app.Listener
is not checked (errcheck)
🪛 LanguageTool
docs/api/fiber.md
[uncategorized] ~233-~233: Possible missing comma found.
Context: ...es. ShutdownWithContext shuts down the server including by force if the context's dea...
(AI_HYDRA_LEO_MISSING_COMMA)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: unit (1.23.x, macos-13)
- GitHub Check: unit (1.23.x, windows-latest)
- GitHub Check: Compare
- GitHub Check: Analyse
- GitHub Check: repeated
🔇 Additional comments (4)
docs/api/fiber.md (1)
233-234
: Documentation accurately reflects implementation changes.The documentation effectively captures the key changes to the
ShutdownWithContext
method, including the guaranteed execution of shutdown hooks through deferred calls and improved error handling.🧰 Tools
🪛 LanguageTool
[uncategorized] ~233-~233: Possible missing comma found.
Context: ...es. ShutdownWithContext shuts down the server including by force if the context's dea...(AI_HYDRA_LEO_MISSING_COMMA)
app_test.go (1)
883-914
: Well-structured test case for successful shutdown!The test case is well-organized with clear setup, execution, and verification steps. It effectively tests the basic shutdown functionality with a fast request.
🧰 Tools
🪛 golangci-lint (1.62.2)
897-897: Error return value of
app.Listener
is not checked(errcheck)
🪛 GitHub Check: lint
[failure] 897-897:
Error return value ofapp.Listener
is not checked (errcheck)🪛 GitHub Actions: golangci-lint
[error] 897-897: Error return value of
app.Listener
is not checked (errcheck)listen.go (1)
500-504
: Add test coverage for the error case.The changes look good and align with the PR objectives to improve the shutdown process. However, line 500 is not covered by tests.
Please add a test case to cover the error scenario in the shutdown process. I can help you generate the test code if needed.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 500-500: listen.go#L500
Added line #L500 was not covered by testslisten_test.go (1)
41-47
: LGTM! Well-structured test cases.The use of sub-tests improves test organization and readability, covering both basic shutdown and shutdown with timeout scenarios.
app_test.go
Outdated
go func() { | ||
serverStarted <- true | ||
_ = app.Listener(ln) | ||
}() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for critical operations.
Several error returns from critical operations are not checked:
app.Listener(ln)
calls on lines 897, 939, and 961- Network operations on lines 968-969
These errors could affect test reliability if they fail silently.
Apply this diff to add error handling:
go func() {
serverStarted <- true
- _ = app.Listener(ln)
+ if err := app.Listener(ln); err != nil {
+ t.Errorf("Failed to start listener: %v", err)
+ }
}()
// In other goroutines...
go func() {
- _ = app.Listener(ln)
+ if err := app.Listener(ln); err != nil {
+ t.Errorf("Failed to start listener: %v", err)
+ }
}()
go func() {
- conn, _ := ln.Dial()
- _, _ = conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"))
+ conn, err := ln.Dial()
+ if err != nil {
+ t.Errorf("Failed to dial: %v", err)
+ return
+ }
+ if _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")); err != nil {
+ t.Errorf("Failed to write: %v", err)
+ }
}()
Also applies to: 937-940, 959-962, 967-970
🧰 Tools
🪛 golangci-lint (1.62.2)
897-897: Error return value of app.Listener
is not checked
(errcheck)
🪛 GitHub Check: lint
[failure] 897-897:
Error return value of app.Listener
is not checked (errcheck)
🪛 GitHub Actions: golangci-lint
[error] 897-897: Error return value of app.Listener
is not checked (errcheck)
} | ||
|
||
// go test -run Test_Listen_Graceful_Shutdown_Timeout | ||
func Test_Listen_Graceful_Shutdown_Timeout(t *testing.T) { | ||
func testGracefulShutdown(t *testing.T, shutdownTimeout time.Duration) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add t.Helper() call.
Since this is a test helper function, add t.Helper()
as the first statement to improve test failure reporting.
func testGracefulShutdown(t *testing.T, shutdownTimeout time.Duration) {
+ t.Helper()
var mu sync.Mutex
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func testGracefulShutdown(t *testing.T, shutdownTimeout time.Duration) { | |
func testGracefulShutdown(t *testing.T, shutdownTimeout time.Duration) { | |
t.Helper() | |
var mu sync.Mutex | |
// ... rest of the function body ... | |
} |
🧰 Tools
🪛 golangci-lint (1.62.2)
50-50: test helper function should start from t.Helper()
(thelper)
errs <- app.Listener(ln, ListenConfig{ | ||
DisableStartupMessage: true, | ||
GracefulContext: ctx, | ||
ShutdownTimeout: 500 * time.Millisecond, | ||
OnShutdownSuccess: func() { | ||
mu.Lock() | ||
shutdownSuccess = true | ||
mu.Unlock() | ||
}, | ||
OnShutdownError: func(err error) { | ||
mu.Lock() | ||
shutdownTimeoutError = err | ||
mu.Unlock() | ||
}, | ||
ShutdownTimeout: shutdownTimeout, | ||
}) | ||
}() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass context to Listener.
The Listener function should receive the context parameter for proper shutdown handling.
-errs <- app.Listener(ln, ListenConfig{
+errs <- app.Listener(ln, ListenConfig{
DisableStartupMessage: true,
GracefulContext: ctx,
ShutdownTimeout: shutdownTimeout,
})
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 golangci-lint (1.62.2)
73-73: Function Listener
should pass the context parameter
(contextcheck)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
app_test.go (3)
883-916
: Enhance test assertions for shutdown state.The test case verifies basic shutdown behavior but could be improved by:
- Adding assertions to verify the server state after shutdown.
- Adding a timeout to prevent the test from hanging if shutdown fails.
t.Run("successful shutdown", func(t *testing.T) { t.Parallel() app := New() + isShutdown := false + app.Hooks().OnPostShutdown(func(err error) error { + isShutdown = true + return nil + }) // Fast request that should complete app.Get("/", func(c Ctx) error { return c.SendString("OK") }) ln := fasthttputil.NewInmemoryListener() serverStarted := make(chan bool, 1) go func() { serverStarted <- true if err := app.Listener(ln); err != nil { t.Errorf("Failed to start listener: %v", err) } }() <-serverStarted // Execute normal request conn, err := ln.Dial() require.NoError(t, err) _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")) require.NoError(t, err) // Shutdown with sufficient timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() err = app.ShutdownWithContext(ctx) require.NoError(t, err, "Expected successful shutdown") + require.True(t, isShutdown, "Server should be in shutdown state") })
932-937
: Address unused parameter in OnPostShutdown hook.The
err
parameter in the OnPostShutdown hook is unused. Consider using_
to explicitly ignore it.-app.Hooks().OnPostShutdown(func(err error) error { +app.Hooks().OnPostShutdown(func(_ error) error { hookMutex.Lock() hookOrder = append(hookOrder, "post") hookMutex.Unlock() return nil })🧰 Tools
🪛 golangci-lint (1.62.2)
[warning] 932-932: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
🪛 GitHub Check: lint
[failure] 932-932:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)🪛 GitHub Actions: golangci-lint
[warning] 932-932: Parameter 'err' seems to be unused, consider removing or renaming it as _.
939-944
: Improve error handling for app.Listener.The error from
app.Listener
should be handled more gracefully.ln := fasthttputil.NewInmemoryListener() +serverErr := make(chan error, 1) go func() { if err := app.Listener(ln); err != nil { - t.Errorf("Failed to start listener: %v", err) + serverErr <- fmt.Errorf("failed to start listener: %w", err) + return } + serverErr <- nil }() + +select { +case err := <-serverErr: + if err != nil { + t.Fatal(err) + } +case <-time.After(100 * time.Millisecond): + // Server started successfully +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app_test.go
(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
app_test.go (1)
Learnt from: efectn
PR: gofiber/fiber#3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.
🪛 golangci-lint (1.62.2)
app_test.go
[warning] 932-932: unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _
(revive)
965-965: Error return value of app.Listener
is not checked
(errcheck)
🪛 GitHub Check: lint
app_test.go
[failure] 932-932:
unused-parameter: parameter 'err' seems to be unused, consider removing or renaming it as _ (revive)
[failure] 965-965:
Error return value of app.Listener
is not checked (errcheck)
🪛 GitHub Actions: golangci-lint
app_test.go
[warning] 932-932: Parameter 'err' seems to be unused, consider removing or renaming it as _.
⏰ Context from checks skipped due to timeout of 90000ms (6)
- GitHub Check: unit (1.23.x, macos-13)
- GitHub Check: unit (1.23.x, macos-latest)
- GitHub Check: unit (1.23.x, windows-latest)
- GitHub Check: Compare
- GitHub Check: Analyse
- GitHub Check: repeated
app_test.go
Outdated
go func() { | ||
_ = app.Listener(ln) | ||
}() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling for app.Listener.
The error from app.Listener
should be handled properly.
+ serverErr := make(chan error, 1)
go func() {
- _ = app.Listener(ln)
+ if err := app.Listener(ln); err != nil {
+ serverErr <- fmt.Errorf("failed to start listener: %w", err)
+ return
+ }
+ serverErr <- nil
}()
+
+ select {
+ case err := <-serverErr:
+ if err != nil {
+ t.Fatal(err)
+ }
+ case <-time.After(100 * time.Millisecond):
+ // Server started successfully
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
go func() { | |
_ = app.Listener(ln) | |
}() | |
serverErr := make(chan error, 1) | |
go func() { | |
if err := app.Listener(ln); err != nil { | |
serverErr <- fmt.Errorf("failed to start listener: %w", err) | |
return | |
} | |
serverErr <- nil | |
}() | |
select { | |
case err := <-serverErr: | |
if err != nil { | |
t.Fatal(err) | |
} | |
case <-time.After(100 * time.Millisecond): | |
// Server started successfully | |
} |
🧰 Tools
🪛 golangci-lint (1.62.2)
965-965: Error return value of app.Listener
is not checked
(errcheck)
🪛 GitHub Check: lint
[failure] 965-965:
Error return value of app.Listener
is not checked (errcheck)
time.Sleep(100 * time.Millisecond) // Wait for request to start | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace sleep with proper synchronization.
Using time.Sleep
for synchronization can lead to flaky tests. Consider using a channel to signal when the request has started processing.
+ requestStarted := make(chan struct{})
app.Get("/", func(c Ctx) error {
+ close(requestStarted)
time.Sleep(2 * time.Second)
return c.SendString("OK")
})
// ... connection setup ...
- time.Sleep(100 * time.Millisecond) // Wait for request to start
+ select {
+ case <-requestStarted:
+ // Request has started processing
+ case <-time.After(time.Second):
+ t.Fatal("Request did not start in time")
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
time.Sleep(100 * time.Millisecond) // Wait for request to start | |
// Add a channel to signal when the request has started processing | |
requestStarted := make(chan struct{}) | |
app.Get("/", func(c Ctx) error { | |
// Signal that the handler has started processing the request | |
close(requestStarted) | |
time.Sleep(2 * time.Second) | |
return c.SendString("OK") | |
}) | |
// ... connection setup ... | |
// Instead of using a fixed sleep, wait for the request to start | |
select { | |
case <-requestStarted: | |
// Request has started processing | |
case <-time.After(time.Second): | |
t.Fatal("Request did not start in time") | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (3)
listen_test.go (1)
74-80
:⚠️ Potential issuePass context to Listener function.
The static analysis tools and pipeline failures indicate that the context parameter should be passed to the Listener function.
go func() { - errs <- app.Listener(ln, ListenConfig{ + errs <- app.Listener(ln, ListenConfig{ DisableStartupMessage: true, GracefulContext: ctx, ShutdownTimeout: shutdownTimeout, }) }()🧰 Tools
🪛 golangci-lint (1.62.2)
75-75: Function
Listener
should pass the context parameter(contextcheck)
🪛 GitHub Check: lint
[failure] 75-75:
FunctionListener
should pass the context parameter (contextcheck)🪛 GitHub Actions: golangci-lint
[error] 75-75: Function
Listener
should pass the context parameter (contextcheck)hooks_test.go (2)
216-220
:⚠️ Potential issueHandle error from app.Listen properly.
The error from
app.Listen
should be properly handled using therequire
package.Apply this diff:
go func() { - if err := app.Listen(":0"); err != nil { - t.Errorf("Failed to start listener: %v", err) - } + require.NoError(t, app.Listen(":0")) }()
230-232
:⚠️ Potential issueUse require.ErrorIs for error comparison.
Replace manual error comparison with
require.ErrorIs
for better handling of wrapped errors.Apply this diff:
-if !errors.Is(receivedErr, expectedErr) { - t.Fatalf("hook received wrong error: want %v, got %v", expectedErr, receivedErr) -} +require.ErrorIs(t, receivedErr, expectedErr, "hook received wrong error")
🧹 Nitpick comments (4)
listen_test.go (2)
64-69
: Consider adding error handling for OnPostShutdown hook.The hook function should handle potential errors that might occur during the shutdown process.
app.hooks.OnPostShutdown(func(_ error) error { mu.Lock() defer mu.Unlock() shutdown = true + if err := someCleanupFunction(); err != nil { + return fmt.Errorf("shutdown cleanup failed: %w", err) + } return nil })
129-145
: Consider using test cleanup for resource management.While the current implementation using
defer
for request and response cleanup is good, consider usingt.Cleanup()
for better test isolation.t.Run(tc.name, func(t *testing.T) { + t.Cleanup(func() { + fasthttp.ReleaseRequest(req) + fasthttp.ReleaseResponse(resp) + }) time.Sleep(tc.waitTime) req := fasthttp.AcquireRequest() - defer fasthttp.ReleaseRequest(req) req.SetRequestURI("http://example.com") resp := fasthttp.AcquireResponse() - defer fasthttp.ReleaseResponse(resp)hooks_test.go (2)
184-200
: Consider adding more test cases for pre-shutdown hooks.The test verifies basic functionality but could be enhanced with:
- Error handling scenarios
- Multiple hooks execution order
- Edge cases (e.g., nil hooks, panic recovery)
Here's a suggested addition:
func Test_Hook_OnPrehutdown(t *testing.T) { + t.Run("successful execution", func(t *testing.T) { t.Parallel() app := New() // ... existing test code ... + }) + + t.Run("error handling", func(t *testing.T) { + app := New() + app.Hooks().OnPreShutdown(func() error { + return errors.New("shutdown error") + }) + require.Error(t, app.Shutdown()) + }) + + t.Run("multiple hooks order", func(t *testing.T) { + app := New() + order := make([]int, 0) + app.Hooks().OnPreShutdown(func() error { + order = append(order, 1) + return nil + }) + app.Hooks().OnPreShutdown(func() error { + order = append(order, 2) + return nil + }) + require.NoError(t, app.Shutdown()) + require.Equal(t, []int{1, 2}, order) + }) }
226-228
: Use require.True for boolean assertions.Replace manual assertion with
require.True
for better test readability and error messages.Apply this diff:
-if !hookCalled { - t.Fatal("hook was not called") -} +require.True(t, hookCalled, "hook was not called")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
app_test.go
(2 hunks)hooks_test.go
(1 hunks)listen_test.go
(2 hunks)
🧰 Additional context used
🧠 Learnings (2)
hooks_test.go (1)
Learnt from: efectn
PR: gofiber/fiber#3162
File: hooks_test.go:228-228
Timestamp: 2024-12-13T08:14:22.851Z
Learning: In Go test files, prefer using the `require` methods from the `testify` package for assertions instead of manual comparisons and calls to `t.Fatal` or `t.Fatalf`.
app_test.go (1)
Learnt from: efectn
PR: gofiber/fiber#3162
File: app_test.go:893-895
Timestamp: 2024-11-29T12:37:27.581Z
Learning: In the `Test_App_ShutdownWithContext` function in `app_test.go`, the `clientDone` channel is used to synchronize the client's request completion before proceeding, eliminating the need for additional `time.Sleep` calls.
🪛 golangci-lint (1.62.2)
listen_test.go
75-75: Function Listener
should pass the context parameter
(contextcheck)
🪛 GitHub Check: lint
listen_test.go
[failure] 75-75:
Function Listener
should pass the context parameter (contextcheck)
🪛 GitHub Actions: golangci-lint
listen_test.go
[error] 75-75: Function Listener
should pass the context parameter (contextcheck)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: unit (1.23.x, macos-13)
- GitHub Check: unit (1.23.x, windows-latest)
- GitHub Check: Analyse
- GitHub Check: Compare
- GitHub Check: repeated
🔇 Additional comments (5)
listen_test.go (3)
40-48
: LGTM! Well-structured test organization.The test has been nicely restructured into sub-tests with clear names and separation of concerns.
50-51
: LGTM! t.Helper() is correctly added.The test helper function correctly includes
t.Helper()
as the first statement.
97-104
: LGTM! Well-structured test cases.The table-driven test approach with clear test case definitions improves readability and maintainability.
Also applies to: 106-123
app_test.go (2)
883-916
: LGTM! Well-structured test with proper synchronization and error handling.The test effectively verifies successful shutdown with:
- Proper error handling for the listener
- Server startup synchronization using channels
- Sufficient timeout duration for shutdown
918-952
: LGTM! Well-implemented hook execution test with proper synchronization.The test effectively verifies hook execution with:
- Thread-safe hook order tracking using mutex
- Clear verification of hook execution order
- Proper error handling for the listener
t.Run("timeout with long running request", func(t *testing.T) { | ||
t.Parallel() | ||
app := New() | ||
|
||
app.Get("/", func(c Ctx) error { | ||
time.Sleep(2 * time.Second) | ||
return c.SendString("OK") | ||
}) | ||
|
||
ln := fasthttputil.NewInmemoryListener() | ||
go func() { | ||
if err := app.Listener(ln); err != nil { | ||
t.Errorf("Failed to start listener: %v", err) | ||
} | ||
}() | ||
|
||
time.Sleep(100 * time.Millisecond) | ||
|
||
// Start long request | ||
go func() { | ||
conn, err := ln.Dial() | ||
if err != nil { | ||
t.Errorf("Failed to dial: %v", err) | ||
return | ||
} | ||
if _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")); err != nil { | ||
t.Errorf("Failed to write: %v", err) | ||
} | ||
}() | ||
|
||
time.Sleep(100 * time.Millisecond) // Wait for request to start | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) | ||
defer cancel() | ||
shutdownErr <- app.ShutdownWithContext(ctx) | ||
}() | ||
|
||
select { | ||
case <-time.After(5 * time.Second): | ||
t.Fatal("idle connections not closed on shutdown") | ||
case err := <-shutdownErr: | ||
if err == nil || !errors.Is(err, context.DeadlineExceeded) { | ||
t.Fatalf("unexpected err %v. Expecting %v", err, context.DeadlineExceeded) | ||
} | ||
} | ||
err := app.ShutdownWithContext(ctx) | ||
require.ErrorIs(t, err, context.DeadlineExceeded) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace sleep-based synchronization with channels for test reliability.
The test correctly verifies timeout behavior, but using time.Sleep
for synchronization can make tests flaky. Consider using channels to synchronize the request start, similar to how clientDone
is used in other tests.
Apply this diff to improve test reliability:
app.Get("/", func(c Ctx) error {
+ requestStarted <- struct{}{}
time.Sleep(2 * time.Second)
return c.SendString("OK")
})
ln := fasthttputil.NewInmemoryListener()
+requestStarted := make(chan struct{})
go func() {
if err := app.Listener(ln); err != nil {
t.Errorf("Failed to start listener: %v", err)
}
}()
-time.Sleep(100 * time.Millisecond)
+select {
+case <-requestStarted:
+ // Request has started processing
+case <-time.After(time.Second):
+ t.Fatal("Request did not start in time")
+}
Committable suggestion skipped: line range outside the PR's diff.
func Test_Hook_OnPostShutdown(t *testing.T) { | ||
t.Run("should execute post shutdown hook with error", func(t *testing.T) { | ||
app := New() | ||
|
||
hookCalled := false | ||
var receivedErr error | ||
expectedErr := errors.New("test shutdown error") | ||
|
||
app.Hooks().OnPostShutdown(func(err error) error { | ||
hookCalled = true | ||
receivedErr = err | ||
return nil | ||
}) | ||
|
||
go func() { | ||
if err := app.Listen(":0"); err != nil { | ||
t.Errorf("Failed to start listener: %v", err) | ||
} | ||
}() | ||
|
||
time.Sleep(100 * time.Millisecond) | ||
|
||
app.hooks.executeOnPostShutdownHooks(expectedErr) | ||
|
||
if !hookCalled { | ||
t.Fatal("hook was not called") | ||
} | ||
|
||
if !errors.Is(receivedErr, expectedErr) { | ||
t.Fatalf("hook received wrong error: want %v, got %v", expectedErr, receivedErr) | ||
} | ||
}) | ||
|
||
t.Run("should execute multiple hooks in order", func(t *testing.T) { | ||
app := New() | ||
|
||
execution := make([]int, 0) | ||
|
||
app.Hooks().OnPostShutdown(func(_ error) error { | ||
execution = append(execution, 1) | ||
return nil | ||
}) | ||
|
||
app.Hooks().OnPostShutdown(func(_ error) error { | ||
execution = append(execution, 2) | ||
return nil | ||
}) | ||
|
||
app.hooks.executeOnPostShutdownHooks(nil) | ||
|
||
if len(execution) != 2 { | ||
t.Fatalf("expected 2 hooks to execute, got %d", len(execution)) | ||
} | ||
|
||
if execution[0] != 1 || execution[1] != 2 { | ||
t.Fatal("hooks executed in wrong order") | ||
} | ||
}) | ||
|
||
t.Run("should handle hook error", func(_ *testing.T) { | ||
app := New() | ||
hookErr := errors.New("hook error") | ||
|
||
app.Hooks().OnPostShutdown(func(_ error) error { | ||
return hookErr | ||
}) | ||
|
||
// Should not panic | ||
app.hooks.executeOnPostShutdownHooks(nil) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add synchronization to prevent race conditions.
The test uses goroutines and shared variables without proper synchronization, which could lead to race conditions.
Consider using a channel or WaitGroup to properly synchronize the test:
func Test_Hook_OnPostShutdown(t *testing.T) {
t.Run("should execute post shutdown hook with error", func(t *testing.T) {
app := New()
+ ready := make(chan struct{})
hookCalled := false
var receivedErr error
expectedErr := errors.New("test shutdown error")
app.Hooks().OnPostShutdown(func(err error) error {
hookCalled = true
receivedErr = err
return nil
})
go func() {
+ defer close(ready)
require.NoError(t, app.Listen(":0"))
}()
- time.Sleep(100 * time.Millisecond)
+ <-ready
app.hooks.executeOnPostShutdownHooks(expectedErr)
// ... rest of the test
})
Committable suggestion skipped: line range outside the PR's diff.
@ReneWerner87 Hi, I have updated the code as per the latest discussion. But I'm having a little go lint glitch. The To solve this problem, you may have to change the signature of the Listener method so that it receives the context parameter directly. This seems to be a long-standing problem. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
listen_test.go (1)
74-80
:⚠️ Potential issuePass context to Listener function.
The static analysis tool correctly identifies that the context parameter should be passed to the Listener function.
-errs <- app.Listener(ln, ListenConfig{ +errs <- app.Listener(ln, ListenConfig{ DisableStartupMessage: true, GracefulContext: ctx, ShutdownTimeout: shutdownTimeout, })🧰 Tools
🪛 golangci-lint (1.62.2)
75-75: Function
Listener
should pass the context parameter(contextcheck)
🪛 GitHub Check: lint
[failure] 75-75:
FunctionListener
should pass the context parameter (contextcheck)🪛 GitHub Actions: golangci-lint
[error] 75-75: Function
Listener
should pass the context parameter (contextcheck)
🧹 Nitpick comments (1)
listen_test.go (1)
97-104
: Consider optimizing struct field alignment.The
testCase
struct's field alignment could be optimized to reduce memory usage.type testCase struct { - name string - expectedErr error - waitTime time.Duration - expectedStatusCode int - closeConnection bool - expectedBody string + expectedErr error // 8 bytes + waitTime time.Duration // 8 bytes + name string // 16 bytes + expectedBody string // 16 bytes + expectedStatusCode int // 4 bytes + closeConnection bool // 1 byte + _ [3]byte // padding }🧰 Tools
🪛 golangci-lint (1.62.2)
97-97: fieldalignment: struct with 64 pointer bytes could be 40
(govet)
🪛 GitHub Check: lint
[failure] 97-97:
fieldalignment: struct with 64 pointer bytes could be 40 (govet)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
listen_test.go
(2 hunks)
🧰 Additional context used
🪛 golangci-lint (1.62.2)
listen_test.go
75-75: Function Listener
should pass the context parameter
(contextcheck)
97-97: fieldalignment: struct with 64 pointer bytes could be 40
(govet)
🪛 GitHub Check: lint
listen_test.go
[failure] 75-75:
Function Listener
should pass the context parameter (contextcheck)
[failure] 97-97:
fieldalignment: struct with 64 pointer bytes could be 40 (govet)
🪛 GitHub Actions: golangci-lint
listen_test.go
[error] 75-75: Function Listener
should pass the context parameter (contextcheck)
⏰ Context from checks skipped due to timeout of 90000ms (6)
- GitHub Check: unit (1.23.x, macos-13)
- GitHub Check: unit (1.23.x, macos-latest)
- GitHub Check: unit (1.23.x, windows-latest)
- GitHub Check: repeated
- GitHub Check: Compare
- GitHub Check: Analyse
🔇 Additional comments (5)
listen_test.go (5)
40-48
: LGTM! Well-structured test organization.The test has been nicely organized into sub-tests with clear scenarios for basic shutdown and timeout cases.
50-51
: LGTM! Helper function follows best practices.The helper function correctly implements
t.Helper()
as the first statement.
82-91
: LGTM! Robust server readiness check.The implementation uses
require.Eventually
for a reliable server readiness check with proper error handling for connection closure.
106-123
: LGTM! Well-structured test cases.The table-driven test cases are well-organized with clear expectations and comprehensive test scenarios.
125-146
: LGTM! Thorough test execution.The test execution is well-implemented with proper resource cleanup using
defer
and clear assertions.
@JIeJaitt |
Description
Optimize
ShutdownWithContext
function and elegant shutdown flow of fiber, streamlineListen
structureChanges introduced
Type of change
Please delete options that are not relevant.
Checklist
Before you submit your pull request, please make sure you meet these requirements:
/docs/
directory for Fiber's documentation.