-
Notifications
You must be signed in to change notification settings - Fork 4
fix: resolve context leak, unseeded jitter, and broken test utility #14
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
base: main
Are you sure you want to change the base?
Conversation
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.
@lupppig Can you please revert back the change in this file?
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.
have done that
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.
@lupppig The PR is still showing this file is being modified, try rebasing the PR.
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.
@mittalyashu done
📝 WalkthroughWalkthroughTwo files modified to improve resource cleanup and randomness handling. In Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
Updated signed commit message template in CLA workflow.
|
I have read the CLA Document and I hereby sign the CLA |
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: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
internal/testutil/testutil.go (1)
11-24: Close the HTTP response body to avoid leaking connections.The response body from
http.Get(url)must be closed to prevent connection leaks and allow the transport to reuse keep-alive connections.🐛 Proposed fix
- if _, err := http.Get(url); err != nil { + resp, err := http.Get(url) + if resp != nil { + defer resp.Body.Close() + } + if err != nil {internal/requestconfig/requestconfig.go (1)
472-484: Canceling the timeout context immediately before reading the response body will cause context-related errors during body reads.When
cancel()is called at line 480 right afterhandler(req), the context becomes cancelled and its error state becomes non-nil. This interferes with subsequent body reading operations (at lines 529 and 560), which may fail withcontext cancellederrors. According to Go'snet/httpsemantics, the request context controls the entire lifetime including response body reading, so the cancellation must be deferred until after the body is fully read or before retrying.The fix should:
- Only cancel the timeout context if it was actually cancelled during the request (move the cancel calls into the error-handling paths)
- Delay cancellation until after body reading completes (after
io.ReadAllcalls)- Cancel before retrying (to prevent accumulation of context resources)
- Rely on the existing
bodyWithTimeoutwrapper for cases where the body is returned without being read immediatelyProposed fix (defer cancel until after body operations)
res, err = handler(req) - - // Close the timeout context for this attempt if one was created - if cancel != nil { - cancel() - cancel = nil - } if ctx != nil && ctx.Err() != nil { + if cancel != nil { + cancel() + cancel = nil + } return ctx.Err() } // Close the response body before retrying to prevent connection leaks if res != nil && res.Body != nil { res.Body.Close() } + if cancel != nil { + cancel() + cancel = nil + } time.Sleep(retryDelay(res, retryCount)) if err != nil { + if cancel != nil { + cancel() + cancel = nil + } return err } contents, err := io.ReadAll(res.Body) res.Body.Close() + if cancel != nil { + cancel() + cancel = nil + } contents, err := io.ReadAll(res.Body) res.Body.Close() + if cancel != nil { + cancel() + cancel = nil + }
🤖 Fix all issues with AI agents
In @.github/workflows/cla.yml:
- Around line 36-37: Replace the hard-coded CLA commit message under the
signed-commit-message key so it uses CLA Assistant Lite template variables
(e.g., $contributorName and $pullRequestNo) instead of "Darasimi Kelani" and
"#14"; update the string to reference $contributorName and $pullRequestNo
(optionally include $owner and $repo) so each signature records the correct
contributor and PR number.
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.
@lupppig The PR is still showing this file is being modified, try rebasing the PR.
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: 1
🤖 Fix all issues with AI agents
In `@internal/requestconfig/requestconfig.go`:
- Around line 479-483: In the ctx.Err() and handler error-return paths, ensure
any non-nil *http.Response returned by the custom HTTPDoer is closed to avoid
connection leaks: before calling cancel() or returning on error, check if resp
!= nil and call resp.Body.Close() (ignoring the close error) and then set resp =
nil; apply this change in the ctx.Err() branch (where cancel is cleared) and in
the handler error-return branch (where handler returns err) so both error paths
mirror the retry-loop cleanup that currently closes resp.Body.
🧹 Nitpick comments (1)
internal/testutil/testutil.go (1)
11-14: Add a timeout to the test server probe.
http.Getuses the default client with no timeout, which can hang tests on stalled DNS/connection attempts. Consider a small timeout or context deadline.🔧 Suggested change
import ( "net/http" "os" "strconv" "testing" + "time" ) func CheckTestServer(t *testing.T, url string) bool { - res, err := http.Get(url) + client := &http.Client{Timeout: 5 * time.Second} + res, err := client.Get(url) if err == nil { res.Body.Close() }
| if ctx != nil && ctx.Err() != nil { | ||
| if cancel != nil { | ||
| cancel() | ||
| cancel = 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.
🧩 Analysis chain
🏁 Script executed:
cat -n internal/requestconfig/requestconfig.go | sed -n '470,495p'Repository: logchimp/logchimp-go
Length of output: 773
🏁 Script executed:
cat -n internal/requestconfig/requestconfig.go | sed -n '450,520p'Repository: logchimp/logchimp-go
Length of output: 2469
🏁 Script executed:
cat -n internal/requestconfig/requestconfig.go | sed -n '520,560p'Repository: logchimp/logchimp-go
Length of output: 1371
🏁 Script executed:
cat -n internal/requestconfig/requestconfig.go | sed -n '400,450p'Repository: logchimp/logchimp-go
Length of output: 1931
🌐 Web query:
http.Client.Do returns response with error Go standard library behavior
💡 Result:
In Go’s standard library (net/http), (*http.Client).Do(req) follows this contract:
- HTTP status codes (including 4xx/5xx) do not produce an error. You get
resp != nil, err == niland must read/closeresp.Body. [1] err != nilmeans either:- a client policy error (most commonly redirect handling via
CheckRedirect), or - a failure to speak HTTP (network/protocol/TLS, etc.). [1]
- a client policy error (most commonly redirect handling via
- The only standard-library case where both
resp != nilanderr != niloccur is whenCheckRedirectfails (including the default redirect policy such as “stopped after too many redirects”). In that case,resp.Bodyis already closed. [1][2] - Any error returned by
Dois a*url.Error(useful forTimeout()checks, etc.). [1]
Practical handling pattern:
resp, err := client.Do(req)
if err != nil {
// resp may be non-nil only on CheckRedirect failure; Body is already closed then.
return err
}
defer resp.Body.Close()Sources: [1] net/http docs for Client.Do (pkg.go.dev) (pkg.go.dev), [2] source-level explanation/examples of the redirect special-case (stackoverflow.com)
Citations:
- 1: https://pkg.go.dev/net/http?utm_source=openai
- 2: https://stackoverflow.com/questions/46423385/when-using-go-http-client-do-method-can-the-httpresponse-and-the-error-be-not-n?utm_source=openai
🏁 Script executed:
rg -n "CustomHTTPDoer" internal/requestconfig/requestconfig.goRepository: logchimp/logchimp-go
Length of output: 166
🏁 Script executed:
rg -B 5 -A 5 "interface.*HTTPDoer\|type HTTPDoer" internal/Repository: logchimp/logchimp-go
Length of output: 46
🏁 Script executed:
rg -n "HTTPDoer" --type goRepository: logchimp/logchimp-go
Length of output: 465
🏁 Script executed:
cat -n internal/requestconfig/requestconfig.go | sed -n '230,240p'Repository: logchimp/logchimp-go
Length of output: 561
🏁 Script executed:
cat -n internal/requestconfig/requestconfig.go | sed -n '1,30p'Repository: logchimp/logchimp-go
Length of output: 889
Close response bodies in all error paths to avoid connection leaks with custom HTTPDoer implementations.
While http.Client.Do typically doesn't return non-nil response with context errors, this code supports custom HTTPDoer implementations that may violate this contract. Additionally, the code inconsistently closes response bodies: it properly closes in the retry loop (line 506-508) but not in error paths.
Two locations need fixing:
- Line 479-484:
ctx.Err()return path - Line 529-534:
handlererror return path
🐛 Suggested fix
if ctx != nil && ctx.Err() != nil {
+ if res != nil && res.Body != nil {
+ res.Body.Close()
+ }
if cancel != nil {
cancel()
cancel = nil
}
return ctx.Err()
}
...
if err != nil {
+ if res != nil && res.Body != nil {
+ res.Body.Close()
+ }
if cancel != nil {
cancel()
cancel = nil
}
return err
}📝 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 ctx != nil && ctx.Err() != nil { | |
| if cancel != nil { | |
| cancel() | |
| cancel = nil | |
| } | |
| if ctx != nil && ctx.Err() != nil { | |
| if res != nil && res.Body != nil { | |
| res.Body.Close() | |
| } | |
| if cancel != nil { | |
| cancel() | |
| cancel = nil | |
| } |
🤖 Prompt for AI Agents
In `@internal/requestconfig/requestconfig.go` around lines 479 - 483, In the
ctx.Err() and handler error-return paths, ensure any non-nil *http.Response
returned by the custom HTTPDoer is closed to avoid connection leaks: before
calling cancel() or returning on error, check if resp != nil and call
resp.Body.Close() (ignoring the close error) and then set resp = nil; apply this
change in the ctx.Err() branch (where cancel is cleared) and in the handler
error-return branch (where handler returns err) so both error paths mirror the
retry-loop cleanup that currently closes resp.Body.
This fixes several issues in the SDK: 1. A context leak in Execute() where the cancel function was deferred incorrectly. 2. Unseeded random jitter in retryDelay(). 3. Improved error reporting in CheckTestServer.
Summary by CodeRabbit
Release Notes
Performance & Reliability
Tests
✏️ Tip: You can customize this high-level summary in your review settings.