Search code examples
dependency-injectionredissignalrautofacsignalr-backplane

SignalR & Autofac - Redis backplane scaleout


I have the following situation: I have a SignalR application in which I use Autofac as a dependency resolver.

public class Startup
{
    public void Configuration(IAppBuilder app)
    { 
        var container = new AutofacContainer().Container;

        var resolver = new AutofacDependencyResolver(container);
        resolver.UseRedis("serverIp", portNumber, "password", "channelName");

        app.UseAutofacMiddleware(container);
        app.MapSignalR(new HubConfiguration
        {
            Resolver = resolver
        });

        resolver.UseRedis("192.168.122.213", 6300, "", "FLEDGG");
        AddSignalRInjection(container, resolver);
    }

    private void AddSignalRInjection(IContainer container,IDependencyResolver resolver)
    {
        var updater = new ContainerBuilder();

        updater.RegisterInstance(resolver.Resolve<IConnectionManager>());
        updater.Update(container);
    }
}

And this is the AutofacContainer class.

public class AutofacContainer
{
    public IContainer Container { get; set; }
    public AutofacContainer()
    {
        var builder = new ContainerBuilder();

        builder.RegisterHubs(Assembly.GetExecutingAssembly())
            .PropertiesAutowired();
        builder.RegisterType<Test>()
            .As<ITest>()
            .PropertiesAutowired();

        Container = builder.Build();
    }
}

Now, the official SignalR Redis scaleout documentation from Microsoft states that I should tell the GlobalHost.DependencyResolver to UseRedis.

    public void Configuration(IAppBuilder app)
    {
        // Any connection or hub wire up and configuration should go here
        GlobalHost.DependencyResolver.UseRedis("server", port, "password", "AppName");
        app.MapSignalR();
    }

Since I don't use GlobalHost anymore in the application (even if I use GlobalHost there is absolutely no behavior in Redis) (as the Autofac integration with SignalR and Owin indicates):

A common error in OWIN integration is use of the GlobalHost. In OWIN you create the configuration from scratch. You should not reference GlobalHost anywhere when using the OWIN integration.

As the Startup class is configured right now:

var resolver = new AutofacDependencyResolver(container);
resolver.UseRedis("serverIp", portNumber, "password", "channelName");

so I create a new resolver of type AutofacDependencyResolver and it connects successfully to the Redis PubSub. The issue however is that if I try to send a single message, that message will repeat itself thousands of times.

(In the Chrome console, for sending a single message from the server I end up in an infinite loop and the client receives it infinitely number of times).

So, the question is: How do I setup SignalR Redis scaleout while using Autofac as dependency resolver (note: there is no circumstance where I can use another dependency resover).

Thanks!

EDIT: If you want further information about the solution, here is the repo without this line:

resolver.UseRedis("serverIp", portNumber, "password", "channelName");

Thanks!

EDIT: I feel like I should clarify some things: If I use resolver.UseRedis();, every message that would be normally sent (once) gets sent many times - so if I subscribe to "channelName" in Redis using subscribe "channelName", I find it to be consistent with the behavior on the client: each message gets sent multiple times.

The next thing to do is have a basic SignalR application without Autofac and see how Redis behaves, although I feel it is an Autofac related issue, more specifically related with the configuration.

Thanks!

UPDATE: Apparently, there is the same behavior in a basic SignalR app without Autofac. The issue has nothing to do with Autofac.


Solution

  • Ok, I found out what was going on:

    The Redis server I was using was configured to have multiple instances running together in a cluster.

    By default, if you have a Redis cluster and publish a message on a channel on any instance, that message will be forwarded by default on all other instance.

    In a Redis Cluster clients can subscribe to every node, and can also publish to every other node. The cluster will make sure that published messages are forwarded as needed. The current implementation will simply broadcast each published message to all other nodes.

    The Redis cluster specification.

    Most likely, the SignalR implementation is configured to take any message coming from Redis, therefore my strange behavior.

    The solution is to have a Redis instance that is not in a cluster and everything works fine.

    If you want to have a SignalR backplane, don't use an instance from a cluster!