7.15.0 (2026-10-06)
Features Added
-
Added an opt-in
try_timeoutclient keyword that bounds a single attempt rather than the whole operation. Applies to sending, management operations (including management-link message settlement), and AMQP link acquisition, where the wait for the link to become ready was previously unbounded. Each attempt gets a freshtry_timeout, still capped by the caller's remaining time; exceeding it raises a retryableOperationTimeoutErrorand retries. Must be greater than 0 if specified, and defaults toNone(off) for other operations; management-link settlement retains a 60-second fallback. It also caps the link acquisition performed byreceive_messages()and by receiver iteration, but does not bound thereceive_messages()long poll, the iterator's own wait, or receiver-link message settlement. Opening, closing and error-path cleanup of the AMQP handler are bounded on the async client, where a slow call is cancelled once the budget is spent and a cleanup failure never replaces the error that triggered it; the sync client cannot interrupt a blocking call and so detects the overrun only once it returns. MirrorsTryTimeoutin the .NET, Java and Go SDKs. -
Added
ServiceBusReceivedMessage.from_bytes()classmethod to construct aServiceBusReceivedMessagefrom raw AMQP payload bytes without requiring the deprecateduamqplibrary. (#43979) -
Added
ServiceBusClient.list_queue_sessions()andServiceBusClient.list_subscription_sessions()(sync and async) to list session IDs for entities with active messages or stored session state, with optional filtering by session-state update timestamp. The methods return anItemPaged[str](AsyncItemPaged[str]on the async client) so callers can iterate every session transparently or page withby_page(). Implements thecom.microsoft:get-message-sessionsmanagement operation. (#46575) -
Added
sql_filter_countandcorrelation_filter_countproperties toTopicRuntimeProperties, exposing the total number of SQL filters and correlation filters across all of a topic's subscriptions. -
Added API version
2024-05and made it the default for the management client, which is required for the topic filter counts above.
Breaking Changes
receive_messages()now returns an empty list after 60 seconds when no wait time was given on the call or the receiver; it previously had no deadline and blocked until a message arrived or the connection closed. An explicitmax_wait_timestill wins, and receiver iteration is unchanged. On a receiver that has not been opened yet, this wait now also bounds the initial link acquisition, including connecting to aNEXT_AVAILABLE_SESSION; open the receiver first (for example with a context manager) to keep that governed solely by the constructor'smax_wait_time.
Bugs Fixed
-
Fixed a bug where the async
AutoLockRenewernever released completed renewal futures from its internal collection, so a long-lived renewer accumulated one entry per registered message for its whole lifetime (memory growth proportional to the total messages processed, reclaimed only onclose()). Each renewal future is now removed as soon as it completes, keeping the collection bounded by the number of active renewals. (#48366) -
Bounded the nesting depth of AMQP compound types (lists, maps, arrays, and described types) in the pyAMQP decoder to a maximum of 64. A payload nested deeper than that is now rejected early with a
ValueError; previously such payloads were bounded only by the Python recursion limit and raisedRecursionError. -
Management, send and receive operations now bound AMQP link acquisition by the caller's timeout, rather than timing only the operation that follows it. Previously a link that never became ready could block indefinitely even when a timeout was supplied. Management and send deduct the time spent from the operation itself, so one attempt shares a single budget.
-
Fixed a bug where messages returned by
receive_deferred_messageshad alock_tokenofNone, which prevented settling (completing, abandoning, dead-lettering, deferring) or renewing the lock on a deferred message inPEEK_LOCKmode. The lock token is now read from thelock-tokenfield of the management-link response for deferred messages. (#42454) -
Read
com.microsoft:max-message-batch-sizevendor property from the AMQP sender link to correctly limit batch size on Premium large-message entities, wheremax-message-sizecan be up to 100 MB but the batch limit is 1 MB. -
Fixed a bug where sending a batched or multi-message payload with
uamqp_transport=TrueraisedTypeError: 'BatchMessage' object is not subscriptable(and a maskedAttributeErroron the list path) when the first message carried amessage_id,session_id, orpartition_key. The batch envelope properties are now set through the transport-appropriate code path. (regression from #42598) -
Fixed a bug where the async receiver factory methods on
azure.servicebus.aio.ServiceBusClient(get_queue_receiver,get_subscription_receiver) and the asyncServiceBusReceiverannotated theauto_lock_renewerkeyword with the synchronousAutoLockRenewer, causing static type checkers to reject the documentedazure.servicebus.aio.AutoLockRenewerusage. The annotation now references the asyncAutoLockRenewer, matching the docstrings and runtime behavior. (#47948) -
Fixed a bug where closing a
PEEK_LOCKreceiver did not release messages that had been prefetched into the client buffer or were still in flight, so they remained locked at the broker until lock expiry — delaying their redelivery and inflating their delivery count. On close, a non-sessionPEEK_LOCKreceiver now drains the link (stopping the broker and flushing in-flight transfers) and releases the buffered messages (releaseddisposition), so the broker can redeliver them immediately without incrementing the delivery count. (#42917) -
Fixed a bug where the async pure-Python AMQP transport failed to connect with
[Errno 22] Invalid argument(amqp:socket-error) inside containerized/virtualized environments such as Docker Desktop on macOS. The transport no longer reads back and re-applies platform-negotiated TCP options (e.g.TCP_MAXSEG) that some platforms reject viasetsockopt. (#45394) -
Fixed a bug where passing a
fully_qualified_namespacethat included a port and/or trailing path (for example thehttps://<namespace>.servicebus.windows.net:443/form that Azure returns when provisioning a namespace) raisedServiceBusAuthenticationError. The namespace is now normalized to its bare host, matching the .NET and JavaScript SDKs. (#44034) -
Fixed a bug where iterating over a
ServiceBusReceiversuppressed automatic HTTP instrumentation (e.g. fromopentelemetry-instrumentation-httpx/requests) while user code processed a received message, causing the user's own outbound HTTP spans to be dropped. The receive tracing span is now closed before the message is yielded to the caller, so suppression no longer leaks into message processing. (#42755) -
Fixed a bug in the pyAMQP transport where decoding an incoming performative whose trailing null fields were omitted by the sender (permitted by AMQP 1.0 section 1.4) raised
IndexError/TypeError. The decoded field list is now padded to the performative's full field count so omitted trailing fields read back as their AMQP-defined default, including the compactlist0encoding where every field is omitted. A field encoded as an explicit null but whose declared default is non-null (for example amax_frame_sizeset to null so the connection would compareNone < 512) now also reads back as that default. -
Fixed a bug where
PEEK_LOCKsettlements on the pure-Python AMQP transport were sent pre-settled even though the receiver link negotiatesrcv-settle-mode=second, so the service's terminal outcome (includingcom.microsoft:message-lock-lostrejections) was discarded and a settlement the service never applied was indistinguishable from success — surfacing only as the message being redelivered at lock expiry. Settlements now wait for the service to confirm the outcome and raise when it is rejected, matching the .NET, Java, JavaScript, and Go SDKs, which all await the disposition unconditionally. This is a behavior change: confirming costs one service round trip per settlement, so settle many messages concurrently rather than one at a time (for exampleawait asyncio.gather(*(receiver.complete_message(m) for m in messages))). Unaffected where outcomes cannot be observed:RECEIVE_AND_DELETEmode anduamqp_transport=True. -
Fixed management-link message settlement fallback after a receiver link is detached. The pyAMQP transport no longer waits for that broken receiver link before using its independent management links, and both management-link acquisition and request/response have a client-side deadline. Settlement uses the configured
try_timeout, or 60 seconds when unset, and keeps retries at the existing outer layer.
Other Changes
- Clarified in the
application_propertiesdocumentation (theServiceBusMessageconstructor, theapplication_propertiesproperty, and the README) that when a message is received, its keys and any string values are returned asbytes, notstr, along with the recommended bytes-key access and decoding pattern. (#45082) - When using the async
AmqpOverWebsockettransport on Python 3.10 or later,aiohttp>=3.14.0is now recommended. Earlieraiohttpversions have a WebSocket heartbeat bug (aio-libs/aiohttp#12030) that can cause the connection to be dropped during long message processing, surfacing as aSocketError("Cannot write to closing transport"). Python 3.9 users must upgrade Python to install anaiohttprelease containing this fix. (#44028) - Management operations (peek, deferred receive, message settlement over the management link, lock renewal, session state, session listing, schedule/cancel) now send
com.microsoft:server-timeout: the caller's remaining time less one second, or 60 seconds when none was given. Previously no bound was sent, so a stalled service held the call until the AMQP link failed; it now raises a retryableOperationTimeoutError, so a persistently stalled service surfaces after roughly four minutes at default retry settings. Matches the .NET, Java and Go SDKs. - Removed the deprecation warning for the legacy uAMQP transport. The
uamqp_transport=Trueoption remains available in 7.15.0.