Closed axelgenus closed 3 years ago
Any reason why you not just delaying the call to serviceProvider.UseRebus()
?
Any reason why you not just delaying the call to
serviceProvider.UseRebus()
?
According to the documentation serviceProvider.UseRebus()
should be called in the Startup.Configure method. It should possible to initialize Rebus engine from a small middleware so that the connection to RabbitMQ is initialized only when the first request is received but... what is supposed to be the "best practice" here?
It should possible to initialize Rebus engine from a small middleware so that the connection to RabbitMQ is initialized only when the first request is received but... what is supposed to be the "best practice" here
Well, it's entirely possible to do that if you want by taking over the configuration of Rebus yourself. The existing .AddRebus(....)
/.UseRebus(...)
methods are only there to encourage you to follow that pattern, but if your hosting environment insists on starting your service before it can connect to stuff, you'll probably need to work around that somehow.
One way could be to leverage Lazy<T>
(available since .NET 4), wrapping the entire Rebus configuration in that:
var lazyBus = new Lazy<IBus>(() =>
Configure.With(...)
.Transport(t => t.(...))
.Start()
);
// pass lazyBus around, get bus via
var bus = lazyBus.Value; //< will initialize the bus the first time it is accessed
(but please remember to dispose the bus somehow, when your program shuts down)
Do you think something like that would work?
Sorry for the delay. I was out-of-office and did not see your answer.
Currently we just make docker-compose restart the service on failure and this did the trick although I don't really like this approach. The major problem with the Lazy<IBus>
you are suggesting is that we use Rebus as a service bus (pub-sub domain events) so we would end up processing queued domain events after the first call to lazyBus.Value
. We are probably going not to use Rebus.ServiceProvider after all and handle the bus creation before the ASP.NET Core application is even started. In this way we can create the IBus instance when the backend is ready and then start the application injecting it in the service collection.
Thank you anyway. I'll publish a Gist or a small sample repo showing how we are going to solve this.
I found myself in a similar situation. My service relies on an input queue and needs to be connected for incoming events. For this reason, I opted for a simple retry strategy (using Polly), rather than a lazy init.
Policy
.Handle<Rebus.Injection.ResolutionException>()
.WaitAndRetryForever(
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
(exception, timespan, context) =>
{
// Add logic to be executed before each retry, such as logging
})
.Execute(() =>
{
app.ApplicationServices.UseRebus();
});
It would be great to have support for Rebus delayed startup of Rebus with the .NET Core service provider.
I found the DelayedStartupConfigurationExtensions static class which seems to work that way. Is it possible to use something like that with .NET Core dependency injection extensions?EDIT: Actually, I found out that the bus is started by means of the DelayedStartupConfigurationExtensions.Create method. The problem is that UseRebus extension method start the Rebus engine immediately. It is a bummer when working with docker-compose (service's dependencies usually takes longer to start than the service itself and the app throws a ResolutionExpection).