Skip to content

fix(servicebus): Read max-message-batch-size vendor property for batch sizing#46197

Open
EldertGrootenboer wants to merge 12 commits intoAzure:mainfrom
EldertGrootenboer:fix/servicebus-batch-size-vendor-property
Open

fix(servicebus): Read max-message-batch-size vendor property for batch sizing#46197
EldertGrootenboer wants to merge 12 commits intoAzure:mainfrom
EldertGrootenboer:fix/servicebus-batch-size-vendor-property

Conversation

@EldertGrootenboer
Copy link
Copy Markdown

@EldertGrootenboer EldertGrootenboer commented Apr 8, 2026

Problem

On Premium large-message Service Bus entities, the AMQP link's max-message-size can be up to 100 MB, but the broker enforces a 1 MB limit for batch sends. The Python SDK infers batch size from the tier by comparing max-message-size against known thresholds ΓÇö this works today but is fragile and doesn't use the actual service-reported value.

Related: azure-service-bus#708

Fix

Read the com.microsoft:max-message-batch-size vendor property from the AMQP sender link remote_properties, which correctly reports 256 KB (Standard) / 1 MB (Premium) independent of entity-level max-message-size. Fall back to the existing tier-based inference when the vendor property is absent (including the uAMQP transport which doesn't expose link properties).

Changes

  • _pyamqp_transport.py: Add get_remote_max_message_batch_size() reading from handler._link.remote_properties
  • _uamqp_transport.py: Add stub get_remote_max_message_batch_size() returning None (uAMQP transport doesn't expose link properties; falls back to tier-based inference)
  • _servicebus_sender.py + _servicebus_sender_async.py: Prefer vendor property, fall back to tier-based inference for both sync and async senders
  • test_batch_sizing.py: 12 new unit tests: transport method (8 tests: present, absent, wrong type, zero, negative, Standard, missing attr) + sender inference (4 tests: vendor override, Premium fallback, Standard fallback, Standard with vendor)

Cross-SDK alignment

SDK Status
.NET Separate PR (same branch pattern)
Java PR #48214
JS Separate PR (same branch pattern)
Go Separate PR (same branch pattern)

CI unblock (added 2026-05-08)

Two Build Analyze sub-tasks were failing on this PR:

  • Verify ChangeLogEntries: _version.py was still 7.14.3; the script then matched the dated 7.14.3 entry and failed because it expected the latest entry to be undated. Fixed by bumping _version.py to 7.14.4 (commit 9027a596eb).
  • Run MyPy: 58 latent errors on main surfaced once mypy became release-blocking. Fixed by binding cast() results to local variables in _pyamqp_transport.py / _uamqp_transport.py (45 errors removed cleanly), one # type: ignore[call-overload] for a bytes-keyed dict.get, and 12 # type: ignore[assignment] on constructor lines in _common/message.py where Optional parameters are passed to non-Optional setters. The setter signature cleanup is intentionally left for a follow-up so this PR stays focused on the batch-size fix (commit 0b35cd33cf).

Verified locally: mypy azure reports Success: no issues found in 112 source files; new + existing message/AMQP unit tests still pass.

…lient (Azure#44999)

- Pass **kwargs from __init__ to _build_pipeline() in both sync and async
  ServiceBusAdministrationClient so transport kwargs (connection_verify,
  transport, policies, ssl_context) reach the transport layer
- Add unit tests verifying kwargs forwarding for both sync and async clients
- Matches pattern from Azure#26015 fix for ServiceBusClient and azure-core base
…h sizing

- Read com.microsoft:max-message-batch-size from AMQP sender link
  remote_properties to correctly limit batch size on Premium
  large-message entities where max-message-size can be up to 100 MB
  but the batch limit is 1 MB
- Add get_remote_max_message_batch_size() to both pyamqp and uamqp
  transport layers (uamqp returns None as it doesn't expose link
  properties, falling back to existing tier-based inference)
- Update both sync and async senders to prefer vendor property
- Add comprehensive unit tests for transport method and sender
  batch size inference
Copilot AI review requested due to automatic review settings April 8, 2026 16:09
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 updates Azure Service Bus sender batch sizing to prefer the service-reported AMQP vendor link property com.microsoft:max-message-batch-size, with a fallback to the existing tier-based inference when the property isn’t available (notably for the uAMQP transport). It also adjusts the management client to forward **kwargs into pipeline construction and adds regression tests.

Changes:

  • Read com.microsoft:max-message-batch-size from pyamqp link remote_properties and use it to set _max_batch_size_on_link (sync + async senders).
  • Add a uAMQP transport stub for the same API (returns None, triggering fallback behavior).
  • Add unit tests for batch sizing and for forwarding management client **kwargs into _build_pipeline.

Reviewed changes

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

Show a summary per file
File Description
sdk/servicebus/azure-servicebus/azure/servicebus/_transport/_pyamqp_transport.py Adds get_remote_max_message_batch_size() reading from pyamqp link remote_properties.
sdk/servicebus/azure-servicebus/azure/servicebus/_transport/_uamqp_transport.py Adds get_remote_max_message_batch_size() stub returning None for uAMQP.
sdk/servicebus/azure-servicebus/azure/servicebus/_servicebus_sender.py Uses vendor batch-size property when available, otherwise falls back to tier inference.
sdk/servicebus/azure-servicebus/azure/servicebus/aio/_servicebus_sender_async.py Async sender mirrors the same vendor-property-first batch sizing behavior.
sdk/servicebus/azure-servicebus/azure/servicebus/management/_management_client.py Forwards **kwargs into _build_pipeline(**kwargs).
sdk/servicebus/azure-servicebus/azure/servicebus/aio/management/_management_client_async.py Async management client mirrors _build_pipeline(**kwargs) forwarding.
sdk/servicebus/azure-servicebus/tests/test_batch_sizing.py Adds unit tests covering vendor property presence/absence and tier fallback logic.
sdk/servicebus/azure-servicebus/tests/test_mgmt_client_kwargs.py Adds regression tests ensuring management client **kwargs reach _build_pipeline (sync + async).

Comment thread sdk/servicebus/azure-servicebus/azure/servicebus/_transport/_pyamqp_transport.py Outdated
Comment thread sdk/servicebus/azure-servicebus/tests/test_batch_sizing.py
Comment thread sdk/servicebus/azure-servicebus/tests/test_batch_sizing.py Outdated
Comment thread sdk/servicebus/azure-servicebus/tests/test_batch_sizing.py Outdated
Comment thread sdk/servicebus/azure-servicebus/tests/test_batch_sizing.py
- Check both bytes and str forms of vendor property key since pyamqp
  decodes AMQP symbols as bytes (b'com.microsoft:max-message-batch-size')
- Update tests to use bytes keys matching production behavior
- Add test for str key fallback
- Remove unused imports, fix docstring
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

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

Comment thread sdk/servicebus/azure-servicebus/tests/test_batch_sizing.py
- Add get_remote_max_message_batch_size to AmqpTransport base class
  for type safety (mypy/IDE)
- Use MAX_MESSAGE_LENGTH_BYTES constant in tests instead of hardcoded 256*1024
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

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

Comment thread sdk/servicebus/azure-servicebus/azure/servicebus/_transport/_uamqp_transport.py Outdated
- Add pylint disable=unused-argument on uamqp stub method
- Add async sender batch size inference tests for parity with sync tests
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

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread sdk/servicebus/azure-servicebus/tests/test_mgmt_client_kwargs.py
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

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Copy link
Copy Markdown
Member

@j7nw4r j7nw4r left a comment

Choose a reason for hiding this comment

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

LGTM

EldertGrootenboer and others added 4 commits May 8, 2026 08:39
The Build Analyze CI job runs mypy on every package and treats it as
release-blocking. azure-servicebus had 58 latent mypy errors on main that
surfaced once mypy became enforced.

Changes:
- _pyamqp_transport.py / _uamqp_transport.py: in to_outgoing_amqp_message,
  bind cast() results to local variables (`header`, `props`) instead of
  reassigning class attributes. mypy does not narrow Optional types through
  reassignment of class attributes; it does narrow through fresh local
  bindings. This removes 45 union-attr errors with no behavior change.
- _uamqp_transport.py: add `# type: ignore[call-overload]` for the single
  bytes-keyed dict.get on properties (mypy can't infer the key type from
  the SESSION_LOCKED_UNTIL constant).
- _common/message.py: add `# type: ignore[assignment]` on 12 constructor
  lines where Optional parameters are assigned to non-Optional property
  setters. Fixing the setters properly is a separate cleanup that should
  not ride along with this batch-size bug fix.
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

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread sdk/servicebus/azure-servicebus/azure/servicebus/_common/message.py Outdated
…tional

Address Copilot review feedback on PR Azure#46197: rather than suppressing the
12 [assignment] mypy errors with `# type: ignore`, widen the setter
signatures to match the actual runtime behavior.

All 12 setters already accept `None` at runtime - they assign to the
underlying Optional AMQP property. The previous non-Optional signatures
were too narrow, which is why the constructor (which legitimately passes
Optional values) needed suppressions.

Changes:
- session_id, message_id, content_type, correlation_id, subject,
  reply_to, reply_to_session_id, to, partition_key: `str` -> `Optional[str]`
- application_properties: `Dict[...]` -> `Optional[Dict[...]]`
- time_to_live: `Union[timedelta, int]` -> `Optional[Union[timedelta, int]]`
- scheduled_enqueue_time_utc: `datetime` -> `Optional[datetime]`
- Remove all 12 `# type: ignore[assignment]` comments from constructor

This is a backward-compatible widening (Liskov-safe). mypy still passes
with zero errors.
EldertGrootenboer added a commit to Azure/azure-sdk-for-js that referenced this pull request May 8, 2026
…ch sizing (#38049)

## Problem

On Premium large-message Service Bus entities, the AMQP link's
`max-message-size` can be up to 100 MB, but the broker enforces a 1 MB
limit for batch sends. The JS SDK reads `max-message-size` (via
`this.link.maxMessageSize`) for batch sizing, so `createMessageBatch()`
accepts batches up to 100 MB that the broker then rejects.

Related:
[azure-service-bus#708](Azure/azure-service-bus#708)

## Fix

Read the `com.microsoft:max-message-batch-size` vendor property from the
AMQP sender link attach frame, which correctly reports 256 KB (Standard)
/ 1 MB (Premium) independent of entity-level `max-message-size`. When
the vendor property is absent (older service versions), fall back to
`Math.min(maxMessageSize, defaultMaxBatchSize)` where
`defaultMaxBatchSize` is 1 MB — this caps the batch size to prevent
using the raw `max-message-size` (which can be up to 100 MB on Premium
large-message entities).

### Changes

- **`messageSender.ts`**: Add `defaultMaxBatchSize` constant (1 MB); add
`getMaxBatchSizeFromLink()` that reads the vendor property from
`this.link.properties`, falling back to `Math.min(maxMessageSize,
defaultMaxBatchSize)`; update `createBatch()` to use the new method
- **`messageSender.spec.ts`**: Unit tests for vendor property present,
absent (with 1 MB cap), undefined properties, wrong type, zero value,
user override, rejection of oversized `maxSizeInBytes`, Standard tier

### Cross-SDK alignment

| SDK | Status |
|-----|--------|
| .NET | [PR
#57941](Azure/azure-sdk-for-net#57941) |
| Java | [PR
#48214](Azure/azure-sdk-for-java#48214) |
| Go | [PR #26530](Azure/azure-sdk-for-go#26530)
|
| Python | [PR
#46197](Azure/azure-sdk-for-python#46197) |

---------

Co-authored-by: Eldert Grootenboer (from Dev Box) <egrootenboer@microsoft.com>
@EldertGrootenboer EldertGrootenboer requested a review from Copilot May 8, 2026 21:25
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

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants