rebus-org / Rebus.SignalR

:bus: Rebus-based SignalR backplane
Other
29 stars 6 forks source link

[Question] Using a Rebus.SignalR backplane in a project already configured to use Rebus #9

Closed ryanbuening closed 4 years ago

ryanbuening commented 4 years ago

I have added Rebus.SignalR to a project that was already configured to use Rebus for other messaging purposes. This throws an exception:

Description: The process was terminated due to an unhandled exception.

Exception Info: System.InvalidOperationException: Sorry, but it seems like Rebus has already been configured in this service collection.

It is advised to use one container instance per bus instance, because this way it can be treated as an autonomous component with the container as the root.

Is there a way around this other than splitting out my SignalR hub into its own separate project/service?

I realize this issue isn't specific to Rebus.SignalR. If this needs moved just let me know.

rsivanov commented 4 years ago

Could you show some fragments of your startup code related to Rebus registration? Rebus.SignalR doesn't register IBus itself, may be you copied the registration by accident.

CzechsMix commented 4 years ago

So We have two use-cases for Rebus in our project. Our messaging solution (configured with out custom serializers and transport settings) and the Rebus as SignalR backplane (with it's own seperate configuration)

If we try to register both with Rebus.ServiceProvider it throws that error.

Would it make sense to have IBus as an optional parameter to the SignalRBackplane method, and use that instance instead of getting one from the service provider?

That way we could still configure our messaging bus with service provider, and configure the backplane with say, the built in activator and just pass that in to install all the SignalR bits.

rsivanov commented 4 years ago

I see, but I don't think it's a good idea to have two different IBus instances with different transport configurations in the same host. Besides IBus we need to get access to BusLifetimeEvents through the DI container (to unsubscribe from backplane events) and that would require to pass two parameters.

At my work I made a completely separate host for SignalR events - that's a lot simpler to manage. For example we have InApp-notifications for different events that a user needs to be alerted about delivered through a SignalR call to Angular application. These notifications are processed by a separate host named Notifications.Client.SignalRHub with its own IBus configuration. You can use the same serialization settings as in other parts of your application there, but the queues should probably be automatically deleted.

    public class SendBankUserInAppMessageHandler : MessageHandlerBase<SendBankUserInAppRequest>
    {
        private readonly IHubContext<InAppHub, IInAppClient> _hubContext;

        public SendBankUserInAppMessageHandler(IMessageHandlerDependencies dependencies,
            IHubContext<InAppHub, IInAppClient> hubContext) : base(dependencies)
        {
            _hubContext = hubContext;
        }

        public override Task Handle(SendBankUserInAppRequest message)
        {
            return _hubContext.Clients.User(Convert.ToString(message.UserId)).ReceiveNotification(message);
        }
    }

    [Authorize]
    public class InAppHub : AuthorizedHubBase<IInAppClient>
    {
    }

    public interface IInAppClient
    {
        Task ReceiveNotification(SendBankUserInAppRequest request);
    }
ryanbuening commented 4 years ago

Thanks for the thoughts rsivanov. I think we are going to separate the SignalR hub into its own host.

rsivanov commented 4 years ago

Thanks for the thoughts rsivanov. I think we are going to separate the SignalR hub into its own host.

Btw, if you're using SqlServer transport, I added AutoDelete option to it in the latest version of Rebus.SqlServer: SqlServerTransportOptions.

The best way to configure SqlServer transport is with the centralized subscriptions and autoDelete option on (if you generate a queue name for the SignalR hub host instance):

.Transport(t => t.UseSqlServer(options, queueName, ).SetAutoDeleteQueue(true))
 .Subscriptions(s => s.StoreInSqlServer(SqlTestHelper.ConnectionString, _subscriptionsTableName, isCentralized: true))
ryanbuening commented 4 years ago

Yes, I saw that update for AutoDelete. I'm using it and everything appears to be working great. Thanks!