Skip to content

fix: honor legacy custom async HTTP clients - #294

Open
mayankbohradev wants to merge 1 commit into
resend:mainfrom
mayankbohradev:fix/legacy-async-client-selection
Open

mayankbohradev wants to merge 1 commit into
resend:mainfrom
mayankbohradev:fix/legacy-async-client-selection

Conversation

@mayankbohradev

@mayankbohradev mayankbohradev commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

What changed

Async requests now use an AsyncHTTPClient assigned to resend.default_http_client when the dedicated async setting still holds the automatic client. A replacement assigned to resend.default_async_http_client retains priority.

The module keeps a private reference to the client created at import time. The dispatcher uses that reference to distinguish the automatic default from a user-supplied client. The README explains the selection order and recommends the dedicated setting for new code.

Why

The original async support documented this configuration:

resend.default_http_client = resend.HTTPXClient(timeout=60)
await resend.Emails.send_async(params)

With httpx installed, module initialization also creates default_async_http_client. The dispatcher selected that non-None client before checking the legacy setting. As a result, the request used the automatic client's 30-second timeout instead of the configured 60-second timeout. A custom subclass's request method was also bypassed.

I reproduced this on upstream 4ce466e before changing the dispatcher. The current dedicated-client configuration already worked and remains the preferred configuration.

How it was tested

  • Ran the unchanged upstream suite first: 701 passed.
  • Added 12 regression and control cases before changing production code: six failed and six passed. After the fix, all 12 passed.
  • Tested public Emails.send_async, Emails.get_async and Usage.get_async calls through the real SDK dispatcher and HTTPX client. httpx.MockTransport supplies the HTTP response. Assertions check the selected client, timeout, request body, authentication and idempotency headers, and returned response headers.
  • Covered explicit dedicated clients, including a plain HTTPXClient; legacy clients; the automatic default; clearing or restoring the dedicated setting; and missing-client and custom-client error behavior.
  • Ran the complete suite on Python 3.9.6 and 3.14.6: 713 passed on each. Lint and mypy passed on both versions.
  • Built the wheel and source distribution. Installed the wheel in fresh environments and checked imports from site-packages with isolated Python execution. Ten checks passed with the async extra; four passed without httpx, including custom async clients and synchronous requests.
  • Replayed the exact patch in a clean upstream export before submission. Full tox passed on Python 3.14; tox -e lint,mypy,py passed on Python 3.9. The four changed files still match the patch after formatting.
  • Ran the repository's Black → isort sequence on the three changed Python files and confirmed that repeating it left their contents unchanged. git diff --check passed.

Commands for the focused and full checks:

python -m pytest -q tests/async_http_client_selection_test.py
tox
# Python 3.9: lint, mypy and complete test suite
tox -e lint,mypy,py
python -m build

The existing Audiences deprecation warnings remain. Python 3.9 also reports an environment warning because its SSL module uses LibreSSL. Package build warnings concern the existing license classifier and universal-wheel settings.

All HTTP responses in these checks are controlled locally. No request was sent to the live Resend API. The full upstream Python version matrix was not run.

Scope

This change restores legacy async configuration while preserving explicit dedicated-client priority. It does not change the synchronous dispatcher, error mapping, dependency versions or connection lifecycle.

Keep a reference to the automatic async client so a legacy custom client
is selected before that default. Preserve priority for a replacement
dedicated client and document the selection order.

Add regression and control tests for dispatch, timeouts and errors.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.28%. Comparing base (7f1acd0) to head (94484f4).
⚠️ Report is 240 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main     #294       +/-   ##
===========================================
+ Coverage   82.66%   97.28%   +14.61%     
===========================================
  Files           4       74       +70     
  Lines          75     4268     +4193     
===========================================
+ Hits           62     4152     +4090     
- Misses         13      116      +103     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions Bot added the linear-synced PR has been synced to Linear label Oct 7, 2026

This branch has not been deployed

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

Labels

linear-synced PR has been synced to Linear

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants