Azure / Azure/azure-sdk-for-python

[ServiceBus] Support properties_to_modify on abandon_message / defer_message / dead_letter_message (feature parity with .NET)

Open
#47,339 2 comments 0 reactions 1 assignee Claimed by @EldertGrootenboer View on GitHub
customer-reported needs-team-attention question Service Attention Service Bus
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.