rebus-org / Rebus

:bus: Simple and lean service bus implementation for .NET
https://mookid.dk/category/rebus
Other
2.3k stars 356 forks source link

avoid rebus to start dequeuing messages at startup #876

Closed sabbadino closed 4 years ago

sabbadino commented 4 years ago

Hi, using

Rebus.AzureServiceBus" version="7.1.3" Rebus" version="6.1.0" Rebus.ServiceProvider" version="5.0.6" Rebus.Serilog" version="6.0.0

I tried with this code services.AddRebus(configure => { return configure .Transport(t => t.UseAzureServiceBusAsOneWayClient( serviceBusSettingsValues.ConnectionString)) .Logging(l => l.Serilog()) .Options(o => { o.UseTopicNameFromMessageFullName(); o.SetMaxParallelism(0); o.SetNumberOfWorkers(0); // this will be enabled if can acquire the lock in the RebusBootstrapper }); }); but this does not work, i get this error.

The maximumCount argument must be a positive number. If a maximum is not required, use the constructor without a maxCount parameter. Parameter name: maxCount Actual value was 0.

The scenario is : Since this code will work in a server farm , where more than one instance can be running ... i want to use a global lock to make sure that rebus will dequeue messages only in one running instance.

The web farm is an azure web app that can be scaled horizontally by devops configuration, It's not possible to deploy a different configuration file for each on the web app instances, nor I can rely on server names.

I tried to move rebus registration staff in a ihostedservice class, but i cannot access iservicecollection and iappbuilder there.

Any other idea to startup up rebus based on some conditions ?

Thank you

sabbadino commented 4 years ago

this seems like solving the issue o.SetMaxParallelism(1); o.SetNumberOfWorkers(0);

then in an ihostedservice class i set _bus.Advanced.Workers.SetNumberOfWorkers(1); if some conditions are satisfied

mookid8000 commented 4 years ago

Good to hear you figured it out šŸ™‚ BUT

you say

(...) i want to use a global lock to make sure that rebus will dequeue messages only in one running instance (...)

and that just happens to be how queues work!

If you have multiple instances of your Rebus service consuming messages off of the same queue, only one of the instances will get each message ā€“ that's the competing consumers pattern at work šŸ™‚

This has the added benefit that you get improved

sabbadino commented 4 years ago

I know that each single message will be received by only one of the instances.

But I want to make sure that only one instance process all messages. The processing logic is based some existing state on a database. Suppose instance A get message N and instance B get message N+1. Processing logic of message N+1 depends on the state of the database that will be changed by message N .. so we have a race condition if instance B is "faster" for any reason than instance A.

As far as I know, there is nothing like rabbit exclusive queues in service bus, which would come handy in my situation.

On Thu, Apr 16, 2020, 09:30 Mogens Heller Grabe notifications@github.com wrote:

Good to hear you figured it out šŸ™‚ BUT

you say

(...) i want to use a global lock to make sure that rebus will dequeue messages only in one running instance (...)

and that just happens to be how queues work!

If you have multiple instances of your Rebus service consuming messages off of the same queue, only one of the instances will get each message ā€“ that's the competing consumers pattern https://www.enterpriseintegrationpatterns.com/patterns/messaging/CompetingConsumers.html at work šŸ™‚

ā€” You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/rebus-org/Rebus/issues/876#issuecomment-614467225, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACHKZFGWKBXCJUCJL66RZJTRM2X2TANCNFSM4MJHUCCQ .

mookid8000 commented 4 years ago

(....) But I want to make sure that only one instance process all messages. (...)

Ah ok, then it makes sense. If possible, I would very much recommend you try and structure your logic so that processing messages A + B is equivalent to processing messages B + A. Over time, this will save you from a lot of trouble šŸ˜

BUT I understand, of course, that it's not always possible to do so, and so it might be necessary to implement the kind of logic you're dealing with.

But yes, setting the number of workers to 0 creates a fully initialized bus that just happens to never process anything, so that's definitely the way to go in your case.