Azure / Azure/azure-sdk-for-python
[ServiceBus] Support properties_to_modify on abandon_message / defer_message / dead_letter_message (feature parity with .NET)
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 3.4k
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 193
Description
**Title:** [ServiceBus] Support `properties_to_modify` on `abandon_message` / `defer_message` / `dead_letter_message` (feature parity with .NET)
## Is your feature request related to a problem?
The .NET SDK allows the caller to modify a message's application properties at settlement time via the `propertiesToModify` parameter, e.g.:
- [`ServiceBusReceiver.AbandonMessageAsync(message, propertiesToModify)`](https://learn.microsoft.com/dotnet/api/azure.messaging.servicebus.servicebusreceiver.abandonmessageasync?view=azure-dotnet)
- `DeferMessageAsync(message, propertiesToModify)`
- `DeadLetterMessageAsync(message, propertiesToModify, ...)`
This is commonly used to pass state back to the broker on retry — for example incrementing a custom retry/attempt counter, or recording the reason/context of an abandon — so that the next consumer of the re-queued message can read it from `application_properties`.
The Python SDK currently provides **no** way to do this. The settlement methods on `ServiceBusReceiver` (sync and async) take only the message:
```python
def complete_message(self, message): ...
def abandon_message(self, message): ... # no properties_to_modify
def defer_message(self, message): ... # no properties_to_modify
def dead_letter_message(self, message, reason=None, error_description=None): ... # reason/description only
```
(see [_servicebus_receiver.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/servicebus/azure-servicebus/azure/servicebus/_servicebus_receiver.py))
This is a cross-language feature parity gap.
## Describe the solution you'd like
Add an optional `properties_to_modify: Optional[Dict[str, Any]] = None` keyword argument to the settlement methods that support it, mapping to the corresponding AMQP delivery outcomes:
- `abandon_message` / `defer_message` → `Modified` outcome (`message-annotations`)
- `dead_letter_message` → `Rejected` outcome (`info` map)
Proposed API (sync + async):
```python
def abandon_message(
self,
message: ServiceBusReceivedMessage,
*,
properties_to_modify: Optional[Dict[str, Any]] = None,
) -> None: ...
def defer_message(
self,
message: ServiceBusReceivedMessage,
*,
properties_to_modify: Optional[Dict[str, Any]] = None,
) -> None: ...
def dead_letter_message(
self,
message: ServiceBusReceivedMessage,
reason: Optional[str] = None,
error_description: Optional[str] = None,
*,
properties_to_modify: Optional[Dict[str, Any]] = None,
) -> None: ...
```
The underlying AMQP stack should already be able to carry these (the `Modified` outcome supports `message-annotations`, and `Rejected` supports an `info` map), so this should mainly be a matter of threading the argument through `_settle_message` to the disposition call.
## Describe alternatives you've considered
- Re-sending a new message with updated properties and completing the original — this breaks delivery-count semantics and at-least-once guarantees, and is not equivalent.
- No clean workaround exists in the current public API.
## Additional context
This was previously requested (for dead-letter only) in #22881, which was auto-closed after 2 years of inactivity without being implemented. That issue explicitly noted the goal of cross-language feature consistency and proposed the `properties_to_modify` naming. This issue broadens the request to `abandon`/`defer` as well, which is where it is most frequently needed.
Note for the Python SDK specifically: `azure-sdk-for-python` does not support sending `propertiesToModify` on abandon today, whereas .NET does.
Contributor guide
Assessment
This issue has not been assessed yet.