Skip to content

fix: add HTTP client timeouts and improve error handling in publish/subscribe/list#99

Open
shedybaba wants to merge 1 commit intogetoptimum:mainfrom
shedybaba:fix/cli-optimization
Open

fix: add HTTP client timeouts and improve error handling in publish/subscribe/list#99
shedybaba wants to merge 1 commit intogetoptimum:mainfrom
shedybaba:fix/cli-optimization

Conversation

@shedybaba
Copy link

@shedybaba shedybaba commented Mar 6, 2026

Summary

  • Replace http.DefaultClient (zero timeout) with a shared httpClient configured with a 30-second timeout in publish, subscribe, and list-topics commands. This prevents the CLI from hanging indefinitely when the remote server is unreachable or slow to respond.
  • Eliminate unnecessary allocation in the HTTP publish path by using bytes.NewReader instead of strings.NewReader(string(...)), avoiding a redundant heap copy of the request payload.
  • Fix bare error return in publish.go — the only return err without context wrapping in the entire function — to provide a descriptive message consistent with all other error returns.
  • Handle io.ReadAll errors in publish and subscribe instead of silently discarding them with _ =, which previously produced empty error messages when the response body couldn't be read.

Motivation

Several commands (health, tracer, update) already use properly configured HTTP clients with explicit timeouts. The publish, subscribe, and list-topics commands were the only ones still using http.DefaultClient, which has no timeout on any stage (DNS, TLS, response headers, body). This is an internal inconsistency and a real operational issue — a user running mump2p publish against a misconfigured or unreachable server would have their terminal freeze with no recovery.

The error handling fixes are in the same code paths and follow patterns already established elsewhere in the codebase (list.go:64, health.go:54).

Changes

File Change
cmd/utils.go Add shared httpClient with 30s timeout
cmd/publish.go Replace DefaultClient, use bytes.NewReader, wrap error, check io.ReadAll
cmd/subscribe.go Replace DefaultClient (4 sites), check io.ReadAll
cmd/list.go Replace DefaultClient (2 sites)

Test plan

  • go build ./... — compiles without errors
  • go vet ./... — no static analysis warnings
  • go test ./... — all unit tests pass
  • Manual: mump2p publish --topic=test --message=hello against unreachable server now times out after 30s instead of hanging

Summary by CodeRabbit

  • Bug Fixes

    • Improved HTTP request reliability by implementing request timeouts to prevent indefinite hangs.
    • Enhanced error messages for failed operations, providing clearer feedback when requests fail.
  • Chores

    • Refactored HTTP client usage across commands for consistency.

…ubscribe/list

Replace http.DefaultClient (zero timeout) with a shared httpClient
configured with a 30-second timeout across publish, subscribe, and
list-topics commands. This prevents the CLI from hanging indefinitely
when the remote server is unreachable or slow to respond.

Other commands in the codebase (health, tracer, update) already use
properly configured HTTP clients — this aligns the remaining commands
with the established pattern.

Additional fixes in the same paths:
- Use bytes.NewReader instead of strings.NewReader(string(...)) in
  publish to avoid an unnecessary heap allocation on every request
- Wrap the bare error return in publish HTTP request creation with
  descriptive context (consistent with all other error returns)
- Check io.ReadAll errors in publish and subscribe instead of silently
  discarding them, which previously produced empty error messages
@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough

Walkthrough

Replaced the default HTTP client with a configured httpClient instance featuring a 30-second timeout across four command files. The new client is initialized in utils.go and used in list.go, publish.go, and subscribe.go. Enhanced error handling for HTTP response body reading in publish.go and subscribe.go.

Changes

Cohort / File(s) Summary
HTTP Client Configuration
cmd/utils.go
Introduced global httpClient variable with 30-second timeout; added imports for net/http and time.
Client Usage Updates
cmd/list.go
Replaced two instances of http.DefaultClient.Do(req) with httpClient.Do(req).
Enhanced Client Usage with Error Handling
cmd/publish.go
Switched to httpClient, changed request body construction from strings.NewReader to bytes.NewReader, added error wrapping for request creation and response body reading; added bytes import.
Client Usage with Response Error Handling
cmd/subscribe.go
Replaced http.DefaultClient with httpClient, added explicit error handling for reading HTTP response body with formatted error messages.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • hpsing
  • Walentalien

Poem

🐰 Hops with glee through timeout lands,
With httpClient in our paws and hands,
No more default clients causing endless waits—
Thirty seconds sharp now seals the fates!
Error catching too, we're quite refined—
A speedy refactor of the kindest kind!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main changes: adding HTTP client timeouts and improving error handling across publish, subscribe, and list commands.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/subscribe.go (1)

159-160: ⚠️ Potential issue | 🟠 Major

Delay signal registration or bind the request to a cancelable context.

signal.Notify is armed before the blocking HTTP subscribe request, but sigChan is not consumed until after the request succeeds. If the server is slow/unreachable and the user presses Ctrl+C during Line 229, the signal is intercepted and the command sits until the 30s HTTP timeout expires. Move the signal.Notify setup below the subscribe call, or create the request with a signal-aware context so Ctrl+C aborts the POST immediately.

Also applies to: 219-229

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/subscribe.go` around lines 159 - 160, The signal handling is registered
before the blocking HTTP subscribe POST and the sigChan isn't consumed until
after the request, so Ctrl+C won't abort the request; fix by creating the HTTP
request with a cancelable context and wiring signals to cancel it (use
context.WithCancel or signal.NotifyContext) so the in-flight subscribe POST can
be aborted on SIGINT/SIGTERM; specifically update the code around
sigChan/signal.Notify and the subscribe HTTP request (use
http.NewRequestWithContext or pass the context into the function that performs
the subscribe call) so the request listens to the cancel context rather than
relying on a later-read sigChan, or alternatively move the signal.Notify setup
to after the subscribe call if you prefer that flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@cmd/subscribe.go`:
- Around line 159-160: The signal handling is registered before the blocking
HTTP subscribe POST and the sigChan isn't consumed until after the request, so
Ctrl+C won't abort the request; fix by creating the HTTP request with a
cancelable context and wiring signals to cancel it (use context.WithCancel or
signal.NotifyContext) so the in-flight subscribe POST can be aborted on
SIGINT/SIGTERM; specifically update the code around sigChan/signal.Notify and
the subscribe HTTP request (use http.NewRequestWithContext or pass the context
into the function that performs the subscribe call) so the request listens to
the cancel context rather than relying on a later-read sigChan, or alternatively
move the signal.Notify setup to after the subscribe call if you prefer that
flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ebb8ce8b-6fdc-4bb0-9564-617a869d6580

📥 Commits

Reviewing files that changed from the base of the PR and between 4f76630 and e0a8117.

📒 Files selected for processing (4)
  • cmd/list.go
  • cmd/publish.go
  • cmd/subscribe.go
  • cmd/utils.go

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant