-
Notifications
You must be signed in to change notification settings - Fork 592
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make handling of publisher confirmations transparent to the user #1682
Comments
This seems like a good list of features/changes for the client to make regarding publisher confirms now that everything is async. After the investigation Daniel and I did regarding #1676, I have some observations about the existing confirmation tracking that I think make sense to include here. The current confirmation tracking that was added relies on the separate use of the When the tracking is moved into the We added this sort of per-message tracking to the NServiceBus RabbitMQ transport a while back, and you can see how this works here.
It's interesting that you mention the Any In the tracking code we added to the transport, we handle the following things and map them back to the
The complication about handling |
I will look into this today. |
Yes, I can see where adding the delivery tag to However, the protocol does guarantee that if a |
Can you explain a bit more about what this means? What's preventing it from being added to the existing text field of Is there something that makes the id just not available at all? |
I just added this comment when you commented 😸 👍 AMQP 0.9.1 does guarantee that if a |
Here is where The ...always returns Adding a header is the best way to address this, or depend on the way the protocol works as I described. |
Relying on the return + ack feels like something really hard to achieve. The header is a bit of a hack, but at least it's reliable and easy to implement. I understand the concerns around adding something to the |
Maybe not ... ??? Thoughts? #1686 Update: nope, no guarantee of when the ack happens (https://www.rabbitmq.com/resources/specs/amqp0-9-1.extended.xml) |
I was going to say that I wasn't aware the broker had that strong of a guarantee of the sequencing of those, just that |
I mean, the spec does say
...and this is what I see in my test program. I'm tracing the code I think the Yes, it does appear that the state flow in |
The docs say the same thing, |
Publisher confirms are a RabbitMQ-specific extension of the AMQP spec, so I'm not sure how much the spec itself would help here anyway. It does seem prudent to know what the broker actually guarantees and if that's actually something "guaranteed" or just an implementation detail. The spike PR was relying on an assumption that the matching |
I forgot about that bit 🤦
Yep, wouldn't that be nice? |
Shouldn't |
@lukebakken correct, RabbitMQ replies with Documentation: |
It seems the client currently doesn't set automatically a message id if non has been set. If we had a message ID that could be used to track states of the return and ACK/NACK sequence by having a secondary index from publish sequence number to IDs. But then I wonder if it wouldn't be better to enforce a sequence number header when the confirms mode is enabled starting from v7. The overhead of that header is super minimal from a size perspective and comparably cheap compared to the decision of doing confirms anyway. |
So what about the following (raw ideas for discussion) Change the ConfirmSelectAsync method to something like /// <summary>
/// Asynchronously enable publisher confirmations.
/// </summary>
/// <param name="maximumNumberOfOutstandingConfirmations">Set to <c>null</c> if tracking via <see cref="BasicAcksAsync"/> and <see cref="BasicNacksAsync"/> yourself.</param>
/// <param name="cancellationToken">CancellationToken for this operation.</param>
Task ConfirmSelectAsync(ushort? maximumNumberOfOutstandingConfirmations = 10,
CancellationToken cancellationToken = default); by default it is set to some upper number of confirms that can be pending. If you want to track it yourself you can set it to null. Internally the channel then makes sure the sequence number acquisition is properly guarded and enforcing the upper limit of number of oustanding confirms. When the upper limits are reached further publish attempts are hold up until for slots are available or the cancellation token triggers.
In non confirms mode the publishes behave like today. In confirms mode they behave in the following way:
The methods Subsequent major releases might flip the default to have confirms enabled but that decision can be postponed. |
I'm also starting to wonder now that acquiring the sequence number is async whether that method should return a scope that makes sure the sequence number cannot be acquired while the scope is active. That would give people tracking acks and nacks manually a chance to have guaranteed exclusive access to the sequence number value on the channel for the duration of the scope (internally acquiring / releasing the consumer semaphore) |
I think it would also make sense to configure the confirms defaults directly during the async channel creation instead of having a dedicated method and deal with all the ramifications of guarding against the value flipping mid way |
@danielmarbach there is no way to disable publisher confirms once enabled. But I have no objections to having it as a constructor argument (or equivalent) at channel creation time. |
Sorry I was thinking about the tracking but wrote confirms defaults (which is ambiguous) because you can call the method multiple times with different flag values today |
Fixes #1682 * Remove `ConfirmSelectAsync` from `IChannel` * Add parameters to enable confirmations on `IConnection.CreateChannelAsync`
@danielmarbach @bording I've done a little bit of work to get the ball rolling here: Basically, just start working to remove the use of |
Fixes #1682 * Remove `ConfirmSelectAsync` from `IChannel` * Add parameters to enable confirmations on `IConnection.CreateChannelAsync`
Fixes #1682 * Remove `ConfirmSelectAsync` from `IChannel` * Add parameters to enable confirmations on `IConnection.CreateChannelAsync`
Fixes #1682 * Remove `ConfirmSelectAsync` from `IChannel` * Add parameters to enable confirmations on `IConnection.CreateChannelAsync`
Fixes #1682 * Remove `ConfirmSelectAsync` from `IChannel` * Add parameters to enable confirmations on `IConnection.CreateChannelAsync` * Remove / comment out all use of `WaitForConfirms...` methods. * Dispose -> DisposeAsync * Implement confirmation tracking and await-ing in `BasicPublishAsync` * Ensure exceptions make into inner exception for `HardProtocolException` * Remove commented-out code related to `WaitForConfirms...` methods. * Unblock so that `CloseAsync` can succeed. * Introduce channel creation options * Allow cancellation of final await for publisher confirmation in `BasicPublishAsync` * Fix `dotnet format` verification error * Make `ConfirmSelectAsync` `private` and assume that semaphore is held. * Track sequence number for basic.return * Implement `basic.return` support. * Fix the code that adds OTel and publish sequence number headers. * Add publish sequence number as long as `_publisherConfirmationsEnabled` is true * Fix the `PublisherConfirms` test program * Add license headers * Enable publisher confirms * Spike an exception based approach (misses removing the bool value return type) * Extend the use of `_confirmSemaphore` to the duration of when exceptions could be caught. * Restore how @danielmarbach serialized the publish sequence number. * Fix bug in how headers are added to `BasicProperties` that don't already have them. * Use `ValueTask` as the `BasicPublishAsync` return value. --------- Co-authored-by: Daniel Marbach <danielmarbach@users.noreply.github.com> Co-authored-by: Luke Bakken <luke@bakken.io> * Add `PublishException` class. * Test that non-routable messages result in `PublishException` with `IsReturn = true` * Code documentation Simplify code.
Re-opening because #1687 implemented only some of the features of this issue. |
Any thoughts on this one? Or is the current thinking with the improved tracking manually doing the sequence acquisition is not longer something desirable and therefore the API usage between acquiring the number and doing the publish doesn't require additional safety nets? |
Hey thanks for bringing that up again. Yes I think that for the vast majority of users, the new tracking features will be more than sufficient. Also, in the history of this project the current sequence number acquisition behavior has been just fine, so we won't need anything else going forward. If we do at some point, it could be added to the existing API, presumably. |
@lukebakken It seems the x-seq is always added channel = await connection.CreateChannelAsync(new CreateChannelOptions
{
PublisherConfirmationsEnabled = true,
}, cancellationToken: cancellationToken).ConfigureAwait(false); Was that deliberate or should it only be added when tracking is enabled? |
If a user enables publisher confirmations, but does not enable tracking, and wants to handle acks/nacks/returns via the events, I thought it would be handy to have that sequence number. Of course, we could also say it's up to the user to add it in the DIY tracking case, too. |
I'm really not that deep in the weeds to be able to say what is best, that's why I formulated it as a question. In my head I was thinking that for manual tracking you need to acquire the next sequence number anyway to store it somewhere to be able to correlate things back. That's why I got curious and started thinking it might only need to be added when publisher confirms tracking is enabled. In all other cases, they can use the constant defined and do things on their own. But again not 100% sure if my mental model holds up |
FYI this is the latest RC upgrade PR Particular/NServiceBus.RabbitMQ#1472. It really simplifies a ton and passes the tests 🙉 |
That's great news! |
Is your feature request related to a problem? Please describe.
Mentioned here.
cc @danielmarbach @bording @Tornhoof
Describe the solution you'd like
CreateChannelAsync
will allow enabling publisher confirmations for the channel, and will allow enabling tracking of confirmations. An options class will be used.BasicPublishAsync
calls will wait indefinitely for the response from the broker. Users may implement a timeout via thecancellationToken
parameter. If a Nack or Return is sent to the client, aPublishException
will be thrown.BasicPublishAsync
will block.Describe alternatives you've considered
Users will be allowed to disable automatic tracking and do it themselves via
BasicAcksAsync
andBasicNacksAsync
Additional context
#1676 (comment)
The text was updated successfully, but these errors were encountered: