Skip to content

Fix outstanding requests overcount with a single atomic counter - #2583

Open
harshal24-chavan wants to merge 1 commit into
drogonframework:masterfrom
harshal24-chavan:bugfix/single-atomic-counter
Open

Fix outstanding requests overcount with a single atomic counter#2583
harshal24-chavan wants to merge 1 commit into
drogonframework:masterfrom
harshal24-chavan:bugfix/single-atomic-counter

Conversation

@harshal24-chavan

Copy link
Copy Markdown
Contributor

What does this PR do?

This PR refactors HttpClientImpl to use a single std::atomic<std::size_t> to track outstanding requests, replacing the previous two-counter system (requestsBufferSize_ and pipeliningCallbacksSize_).

Why is this needed?

Previously, reading outstandingRequests() could yield inconsistent snapshots. Because requestsBuffer_ and pipeliningCallbacks_ were tracked by independent atomics, which could lead to undercount / overcount of the total requests.

How does this fix it?

By transitioning to a single lifecycle-based counter:

  1. outstandingRequests_.fetch_add(1) is called exactly once when a request enters sendRequestInLoop.
  2. outstandingRequests_.fetch_sub(1) is called when a request is fully completed, aborted, or times out.

This completely eliminates the undercount / overcount, makes the tracking mathematically sound regardless of thread timing, and allowed for the removal of several redundant queue helper functions, simplifying the class API.

Changes:

  • Replaced 2 atomic variables with outstandingRequests_.
  • Removed enqueueRequest, popFrontRequest, and eraseRequest helpers.
  • Removed requestsBufferSize() from the public HttpClient API (updated example and test to match).

@an-tao

an-tao commented Sep 6, 2026

Copy link
Copy Markdown
Member

@harshal24-chavan thanks for this PR.

The single-counter approach looks correct and I don't see an obvious lifecycle/double-decrement issue. However, I don't think requestsBufferSize() should be removed from the public HttpClient API in this refactor.

Removing it is a source-breaking API change, while the counter consolidation does not require removing the API. requestsBufferSize() can still be implemented from requestsBuffer_.size() since the queue is accessed on the event-loop thread.

Please consider keeping the existing API for backward compatibility and add explicit tests for timeout and connection-error paths to verify that every request is decremented exactly once.

@harshal24-chavan

Copy link
Copy Markdown
Contributor Author

Thanks for the review @an-tao.

Understood, I'll revert back the requestsBufferSize() function changes, and update the tests.

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.

3 participants