Skip to content

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

@shingo-kurimoto-ulsystems

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.:

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:

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)

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_messageModified outcome (message-annotations)
  • dead_letter_messageRejected outcome (info map)

Proposed API (sync + async):

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    customer-reportedIssues that are reported by GitHub users external to the Azure organization.needs-triageWorkflow: This is a new issue that needs to be triaged to the appropriate team.questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions