Skip to content

[ServiceBus] Fix async sender AttributeError race in _open (#35618)#46683

Open
SAY-5 wants to merge 2 commits intoAzure:mainfrom
SAY-5:fix/sender-async-attr-none-35618
Open

[ServiceBus] Fix async sender AttributeError race in _open (#35618)#46683
SAY-5 wants to merge 2 commits intoAzure:mainfrom
SAY-5:fix/sender-async-attr-none-35618

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented May 2, 2026

Description

Fixes #35618.

When multiple coroutines concurrently call ServiceBusSender.send_messages on a shared async sender, a race in _servicebus_sender_async.py:_open can null out self._handler between await self._handler.open_async(...) and await self._handler.client_ready_async(), producing:

AttributeError: 'NoneType' object has no attribute 'client_ready_async'

This patch captures self._handler into a local variable immediately after _create_handler(auth) and uses that local for the subsequent awaits within _open. The except/_close_handler cleanup path still operates on self._handler, preserving existing teardown semantics.

All SDK Contribution checklist:

  • The pull request does not introduce [breaking changes]
  • CHANGELOG is updated for new features, bug fixes or other significant changes.
  • I have read the contribution guidelines.

General Guidelines and Best Practices

  • Title of the pull request is clear and informative.
  • There are a small number of commits, each of which have an informative message.

Testing Guidelines

  • Pull request includes test coverage for the included changes. (The race is timing-dependent and difficult to reproduce deterministically in a unit test without restructuring the handler lifecycle; the patch is a defensive local-capture that does not change observable behavior on the happy path.)

Capture self._handler into a local before awaiting open_async/client_ready_async so a concurrent coroutine cannot null it out mid-flight, addressing the AttributeError reported in Azure#35618.

Signed-off-by: SAY-5 <saiasish.cnp@gmail.com>
Copilot AI review requested due to automatic review settings May 2, 2026 23:00
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

Thank you for your contribution @SAY-5! We will review the pull request and get back to you soon.

@github-actions github-actions Bot added Community Contribution Community members are working on the issue customer-reported Issues that are reported by GitHub users external to the Azure organization. Service Bus labels May 2, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to fix a concurrency bug in the async Service Bus sender by making _open() use a local handler reference, so shared ServiceBusSender instances are less likely to hit an AttributeError during concurrent sends. It fits into the azure-servicebus package's async connection lifecycle, specifically around sender startup and readiness checks.

Changes:

  • Updated ServiceBusSender._open() to capture self._handler in a local variable before awaited startup calls.
  • Switched handler-dependent readiness and max-message-size logic in _open() to use the captured local handler.
  • Added a changelog entry describing the async sender race-condition fix.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
sdk/servicebus/azure-servicebus/azure/servicebus/aio/_servicebus_sender_async.py Adjusts async sender open logic to use a local handler reference during awaited startup.
sdk/servicebus/azure-servicebus/CHANGELOG.md Documents the intended bug fix for the upcoming unreleased version.

Comment on lines +212 to +219
handler = self._handler
try:
await self._handler.open_async(connection=self._connection)
while not await self._handler.client_ready_async():
await handler.open_async(connection=self._connection)
while not await handler.client_ready_async():
await asyncio.sleep(0.05)
self._running = True
self._max_message_size_on_link = (
self._amqp_transport.get_remote_max_message_size(self._handler) or MAX_MESSAGE_LENGTH_BYTES
self._amqp_transport.get_remote_max_message_size(handler) or MAX_MESSAGE_LENGTH_BYTES
Comment on lines +203 to +214
try:
await self._handler.open_async(connection=self._connection)
while not await self._handler.client_ready_async():
await handler.open_async(connection=self._connection)
Capture critical section in a per-sender lock so concurrent coroutines
cannot race on creating and closing self._handler. Re-checks _running
inside the lock so the loser of the race no-ops cleanly.

Signed-off-by: SAY-5 <say.apm35@gmail.com>
@SAY-5
Copy link
Copy Markdown
Author

SAY-5 commented May 3, 2026

Addressed the serialization concern in f568e44: wrapped the create/open critical section in a per-sender asyncio.Lock (lazily initialised on first _open()), with a double-check on _running after acquiring so the loser of the race exits cleanly. The local-handler capture stays as a defence-in-depth on the awaited startup path inside the lock.

I left out a regression test in this commit — the package's existing test infra runs against live Service Bus (test_proxy fixture, no async sender mock harness today). Happy to add a unit test alongside if you'd like, but it would mean introducing a mock sender pattern that doesn't yet exist here, which felt like a separate change to keep this fix reviewable. Let me know your preference.

@SAY-5
Copy link
Copy Markdown
Author

SAY-5 commented May 3, 2026

Heads-up: the Azure DevOps Build Test (Ubuntu2404_313) and Build Analyze are red on f568e44 but I can't see the pipeline log without an azure-sdk org account. Local python -m pytest sdk/servicebus/azure-servicebus/tests/async_tests -k sender is green and the file passes ast.parse. If a maintainer can share the relevant log lines (mypy/pylint/test name) I'll fix immediately.

@SAY-5
Copy link
Copy Markdown
Author

SAY-5 commented May 3, 2026

Reproduced the Build Analyze pyright error locally — the reportIncompatibleMethodOverride on _open is pre-existing on main as well, not introduced by this PR. Happy to follow up with a separate annotation fix if desired.

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

Labels

Community Contribution Community members are working on the issue customer-reported Issues that are reported by GitHub users external to the Azure organization. Service Bus

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[servicebus] AttributeError: 'NoneType' object has no attribute 'client_ready_async' when reusing async ServiceBusSender objects

2 participants