GithubHelp home page GithubHelp logo

Comments (12)

SeanFeldman avatar SeanFeldman commented on May 29, 2024

@ncarandini 👍 for better documentation. The current client (not this repo) is doing a horrible job.

But to be fair, this client in this repo is providing the xmldoco, which is an improvement 😃

This is why I had #26 from day one.
/cc @jtaubensee @nemakam

from azure-service-bus-dotnet.

ncarandini avatar ncarandini commented on May 29, 2024

Ops, I totally missed it!
I just found the How can we improve the Windows Azure Service Bus? where you explain that the current client is not on GitHub.

Thanks a lot for your clarifying comment.

I'll close this issue as is unrelated to this repo. Sorry for the mess.
I'll also read this library code looking for same behavior and if needed I'll open a new issue, this time with a request for PeekLock default behavior.

from azure-service-bus-dotnet.

ncarandini avatar ncarandini commented on May 29, 2024

Hi @jtaubensee, I cloned this repo and saw that the same issue is present here.
Now I've more things to say, pointing to specific code lines of MessageReceiver.cs , OnMessageOptions.cs, MessageReceivePump.cs and QueueClient.cs.
Do you prefer me to open a new issue or reopen this one, removing (by you, if you'll think is ok) the invalid tag ?

from azure-service-bus-dotnet.

ncarandini avatar ncarandini commented on May 29, 2024

Thanks @jtaubensee,
I'll procede here :-)

from azure-service-bus-dotnet.

jtaubensee avatar jtaubensee commented on May 29, 2024

Hi @ncarandini -

So the default behavior is still peek lock, however we default the value OnMessageSettings.AutoComplete to true. This means that when the OnMessage callback exits, Message.Complete is called. If you were to call Message.Abandon or Message.Defer inside of your OnMessage callback, the message would still exist on the queue.

ReceiveDelete means that when the message is retrieved from the queue, it is also deleted from the queue. While this performance can be better, it can result in message loss, if your receiver dies while processing the message.

Does that make sense? To your point, our documentation could do a better job of explaining this.

from azure-service-bus-dotnet.

ncarandini avatar ncarandini commented on May 29, 2024

As stated before, I do think that the default behavior of the OnMessage should be PeekLook and this will not be the case if the AutoComplete is set to true.

These are my proposals:

Set AutoComplete to false as the default value

Looking at the OnMessageOptions.cs we see that the constructor set the default options:

public OnMessageOptions()
{
    this.MaxConcurrentCalls = 1;
    this.AutoComplete = true;
    this.ReceiveTimeOut = Constants.DefaultOperationTimeout;
    this.AutoRenewTimeout = Constants.ClientPumpRenewLockTimeout;
}

The easiest things will be to change it to:

...
this.AutoComplete = false;
...

or to add a line in the Microsoft.Azure.ServiceBusCostants class and reference it:

...
this.AutoComplete = Constants.DefaultAutoComplete;
...
namespace Microsoft.Azure.ServiceBus
{
    using System;
    internal static class Constants
    {
        ...
        public const bool DefaultAutoComplete = false;
        ...
    }
}

Inherit the value of AutoComplete from the Mode value of the MessageReceiver (of the QueueClient)

From now on, I'll refer only to the MessageReceiver, because calling the QueueClient.OnMessageAsync() method calls the same method of the QueueClient.InnerReceiver (of type MessageReceiver) and because I take for granted that the QueueClient.InnerReceiver.Mode property will have the same value of the QueueClient.Mode one.

That being said, calling te MessageReceiver.OnMessageAsync() method without the optional OnMessageOptions parameter, will actually produce a call to the more complete method passing a new instance of OnMessageOptions class with the default values created as we've seen before with the notable exception of the ReceiveTimeOut, that is inherited from the value of the corresponding property of the caller (i.e. the MessageReceiver instance):

public void OnMessageAsync(Func<BrokeredMessage, CancellationToken, Task> callback)
{
    this.OnMessageAsync(callback, new OnMessageOptions() {
        ReceiveTimeOut = this.OperationTimeout
    });
}

My suggestion is to inherit also the AutoComplete from the caller Mode value, with a very simple type conversion:

public void OnMessageAsync(Func<BrokeredMessage, CancellationToken, Task> callback)
{
    this.OnMessageAsync(callback, new OnMessageOptions() {
        ReceiveTimeOut = this.OperationTimeout,
        AutoComplete = this.ReceiveMode == ReceiveMode.ReceiveAndDelete
    });
}

@jtaubensee, if you think this has some meaning, I can make a PR of it.

from azure-service-bus-dotnet.

jtaubensee avatar jtaubensee commented on May 29, 2024

@ncarandini - Did you see my previous message? I understand what you are saying, however there seems to be a disconnect.

Today, there are two different receive modes in Service Bus. Below is a description of each:

This operation atomically retrieves and locks a message from a queue or subscription for processing. The message is guaranteed not to be delivered to other receivers (on the same queue or subscription only) during the lock duration specified in the queue/subscription description. When the lock expires, the message becomes available to other receivers. In order to complete processing of the message, the receiver should issue a delete command with the lock ID received from this operation. To abandon processing of the message and unlock it for other receivers, an Unlock Message command should be issued, otherwise the lock duration period can expire.

This operation should be used in applications that require At-Least-Once delivery assurances. If the receiver does not delete the message before processing succeeds, this ensures that another receiver is able to attempt processing after the lock duration period expires.

This operation receives a message from a queue or subscription, and removes the message from that queue or subscription in one atomic operation.

With that said, I believe this is different from what you are talking about. Aren't you basically suggesting that OnMessageOptions.AutoComplete should be set to false by default? Here is a description of AutoComplete.

The reason that it is set to true, is so that you don't always have to call Message.Complete inside of OnMessage. In the past we had some customers who forgot to do so, and then a message would keep appearing, until it was eventually dead-lettered. We really are promoting OnMessage as the easiest way to get up and running with Service Bus. It can be hard to develop your own receive pump, and we see customers who do it incorrectly all the time. They can very easily get a high bill because they call too often or inefficiently.

The only place that AutoComplete is used is here:

if (this.messageReceiver.ReceiveMode == ReceiveMode.PeekLock &&
	this.registerHandlerOptions.AutoComplete)
{
	await this.messageReceiver.CompleteAsync(new[] { message.LockToken }).ConfigureAwait(false);
}

which in turn is then called here, after OnMessage has completed.

from azure-service-bus-dotnet.

ncarandini avatar ncarandini commented on May 29, 2024

Hi @jtaubensee,
thanks for your kind explanation, now I can better understand the historical reasons of the default value of true of the AutoComplete option.

Nevertheless, while I can understand this is a safety rail for beginners, I still think this is misleading for most developers. On my opinion, using the library message pump vs. manually requesting a message shouldn't change the behaviour set by the ReceiveMode, unless I (as a developer) opt to the safety rail of AutoComplete = true.

Anyway, on the current .NET library (I still don't know if also in the current repro, I haven't tested it yet), there is no difference from having (ReceiveMode = PeekLook & AutoComplete = true) versus (ReceiveMode = ReceiveAndDelete) because the message is removed from the queue even if the handler method got an ErrorException.

Here's my test code:

...
client.OnMessage(receivedMessage =>
{
    try
    {
        // To check the OnMessage behaviour we force an Exception Error
        throw new Exception("Exception thrown to test message pump behavior");

        // Do something with the message

        // We are using the message pump that has the AutoReceive set to true by default.
        // No need to call receivedMessage.Complete();
    }
    catch (Exception ex)
    {
        WriteLineColor($"Error processing MessageId {receivedMessage.MessageId}: {ex.Message}", ConsoleColor.Red);
        Console.WriteLine();
    }
});
...

If confirmed, this must be a bug.

from azure-service-bus-dotnet.

jtaubensee avatar jtaubensee commented on May 29, 2024

@ncarandini - To be clear, AutoComplete is only ever used for OnMessage / Receive pump (which are two words for the same thing). AutoComplete is not a property for ReceiveAsync().

What we are talking about here are two different things. Just because AutoComplete is set to true, does not mean that the ReceiveMode becomes ReceiveDelete. It simply means that we call Message.Complete() for you when your lambda is done executing. If there is an error inside of that lamda, we do not call complete, and the message is available for processing again on the queue.

If you have ReceiveMode set ReceiveDelete then there is never a reason to call Message.Complete as the message is already removed from the queue.

Can you share your code that shows AutoComplete when there is an exception in your OnMessageHandler? FYI - the implementations of that message pump / OnMessage are the same between this library and the .NET Framework NuGet package.

from azure-service-bus-dotnet.

ncarandini avatar ncarandini commented on May 29, 2024

Yes, AutoComplete is indeed a property of OnMessageOptions and it solely purpose is to call message.Complete inside the OnMessage code, only if it is true AND the handled method works fine (i.e. no ErrorException thrown). This is (finally) clear to me.

My implementation was wrong, because I was catching the error so the handled method completed successfully.

So, at the end of the story, only better documentation is needed to explain why, when and how to set AutoComplete to false.

Even the ReceiveSample use it:

// Register a OnMessage callback
queueClient.RegisterMessageHandler(
    async (message, token) =>
    {
        // Process the message
        Console.WriteLine($"Received message: SequenceNumber:{message.SequenceNumber} Body:{message.GetBody<string>()}");

        // Complete the message so that it is not received again.
        // This can be done only if the queueClient is opened in ReceiveMode.PeekLock mode.
        await queueClient.CompleteAsync(message.LockToken);
    },
    new RegisterHandlerOptions() {MaxConcurrentCalls = 1, AutoComplete = false});

Thanks for all the time spent on answering my question.

from azure-service-bus-dotnet.

SeanFeldman avatar SeanFeldman commented on May 29, 2024

The swallowed exception has tricked you 😃

from azure-service-bus-dotnet.

ncarandini avatar ncarandini commented on May 29, 2024

I must wear the donkey hat for at least a week!
1635a17d5a4ad160fd511cfc2f5b1b92

from azure-service-bus-dotnet.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.