Skip to content

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

Open
SAY-5 wants to merge 1 commit 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 1 commit 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
async def _open(self):
if self._running:
return
if self._handler:
await self._handler.close_async()
auth = None if self._connection else (await create_authentication(self))
self._create_handler(auth)
# Capture a local reference to the handler to guard against concurrent
# coroutines mutating self._handler across awaits (see issue #35618).
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)
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