Azure / Azure/azure-sdk-for-cpp

WS9: Restore the receiver prefetch option on the Rust AMQP transport

Open
#7,271 0 comments 0 reactions 1 assignee Claimed by @j7nw4r View on GitHub
Event Hubs
Dominant language
C++
Stars
205
Forks
172
Avg merge
1d 3h
Merged PRs (30d)
37

Description

## Summary

The Rust AMQP transport ignores the receiver prefetch option. `PartitionClientOptions::Prefetch` and `ProcessorOptions::Prefetch` are public options. Their documented default is 300, and a negative value disables the prefetch. The Event Hubs client copies these options into `MessageReceiverOptions::MaxLinkCredit`. The uAMQP transport sends that value to the wire. The Rust transport does not read it. Each receiver link therefore attaches with the Rust crate default of 100 credits.

The Rust transport is the default transport today (`sdk/core/azure-core-amqp/CMakeLists.txt:36`). A default build therefore has a public option that does nothing.

The AMQP transport decision in #7253 gates this item. The severity tags below apply if that decision selects the Rust transport. If the decision selects the uAMQP transport, this item closes with no code change. The severity tags follow the key in #7252. All code anchors refer to commit `f1039fe23`.

## Motivation

AMQP link flow control is receiver driven. The receiver grants the link credit. The sender must stop when the credit becomes zero. The prefetch option sets that credit. It controls how many events the service sends before the client grants more credit.

The Event Hubs client sets the credit in both transport branches. `src/partition_client.cpp:130-133` and `:162-167` each contain the comment "Set the link credit to the prefetch count". Each branch assigns `receiverOptions.MaxLinkCredit = options.Prefetch`. The documented default is 300 (`inc/azure/messaging/eventhubs/partition_client.hpp:50`, `inc/azure/messaging/eventhubs/processor.hpp:61`).

The uAMQP receiver sends the value to the wire. `src/impl/uamqp/amqp/message_receiver.cpp:121-123` tests `m_options.MaxLinkCredit != 0`. It then calls `m_link->SetMaxLinkCredit`.

The Rust receiver discards the value. `MessageReceiverImpl::Open` sets the name, the receiver settle mode, the target, and the properties. It then calls `amqpmessagereceiver_attach` (`src/impl/rust_amqp/amqp/message_receiver.cpp:131-178`). It never sets the credit. The `MaxLinkCredit` field stays commented out at `src/impl/rust_amqp/amqp/message_receiver.cpp:129`.

The Rust crate default reaches the wire instead. `rust_amqp/azure_core_amqp/src/fe2o3/receiver.rs:59` calls `options.credit_mode.clone().unwrap_or_default()`. `rust_amqp/azure_core_amqp/src/receiver.rs:32-34` sets that default to `ReceiverCreditMode::Auto(100)`.

The three documented behaviors therefore become one fixed value of 100 credits on a default build:

| Documented behavior | The uAMQP transport | The Rust transport |
|---|---|---|
| `Prefetch` has a default of 300 | 300 credits | 100 credits |
| `Prefetch` has a value of N | N credits | 100 credits |
| A `Prefetch` value below 0 disables the prefetch | the uAMQP default applies | 100 credits |

Both sides of the language boundary have the necessary capability. Only the call between them is missing. The FFI exports `amqpmessagereceiveroptions_set_credit_mode` (`rust_amqp/rust_wrapper/src/amqp/message_receiver.rs:382`). That function accepts a `RustReceiverCreditMode { manual: bool, credit_mode: u32 }` (`:375-379`). It then sets `ReceiverCreditMode::Manual` or `ReceiverCreditMode::Auto(n)`. No C++ code calls this function.

The impact is silent. A caller who increases `Prefetch` to adjust the receive throughput sees no change. A caller who sets `Prefetch` below zero to disable the prefetch still receives events. The library reports no error to either caller. No test finds the difference.

One related item needs an examination, but not a fix in this issue. The FFI also exports `amqpmessagereceiveroptions_set_auto_accept`. No C++ code calls that function either.

## Proposal

- [ ] Set the credit mode in `MessageReceiverImpl::Open` on the Rust transport (`src/impl/rust_amqp/amqp/message_receiver.cpp:131-178`). The FFI entry point exists already. **[GA blocker]**
- [ ] Delete the commented `MaxLinkCredit` field at `src/impl/rust_amqp/amqp/message_receiver.cpp:129`. **[GA blocker]**
- [ ] Decide how `MessageReceiverOptions::MaxLinkCredit` shows a disabled prefetch, and record the decision in this issue. The C++ option is a `uint32_t` with a default of 0. `src/partition_client.cpp:130` assigns it only when `Prefetch` is 0 or more. A disabled prefetch is therefore the same as an option that the caller did not set. The Rust side shows the disabled condition as `ReceiverCreditMode::Manual`. **[GA blocker]**
- [ ] Examine the Rust receiver shim for more options that `Open` discards. Start with the auto accept option. **[GA blocker]**
- [ ] Add an offline test that makes sure the receiver attaches with the requested credit. This test is cheap, and it finds this defect. **[GA blocker]**
- [ ] Make the two transport branches at `src/partition_client.cpp:128-133,162-167` agree after the fix. #7253 can also remove one of the two branches. **[GA quality bar]**
- [ ] Add a live test that shows a different `Prefetch` value changes the receive behavior. **[GA quality bar]**

## Validation

- [ ] A receiver with the default options attaches with 300 credits on the transport that #7253 selects.
- [ ] A receiver with a custom `Prefetch` value attaches with that value.
- [ ] A receiver with a `Prefetch` value below zero operates as the recorded decision states.
- [ ] The offline credit test passes. This test fails today on the Rust transport, and it must pass after the fix.
- [ ] The path from the Event Hubs client to the wire discards no other `MessageReceiverOptions` field.

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.