Rebus /基于内容的路由

时间:2016-11-19 16:21:07

标签: rebus

Tree Structure

如您所见,总部作为根节点,一些分支作为子节点。有一条 Data 类型的消息,我想根据 Data 对象的内容发布消息,例如:

if (data.value == xxxx) publish(data, Br1, Br2)
else if (data.value == yyyy) publish(data, Br3, Br4)
else if (data.value == zzzz) publis(data, Br5, Br6)

这是某种方式的pub / sub模式的定制版本。但我希望根据消息内容向一些特殊订阅者发布类型为Data的消息。

Rebus有解决方案吗?

4 个答案:

答案 0 :(得分:0)

Rebus有几种解决方案:)

对于您的场景,我可以看到两种解决方案:1)使用自定义主题,或2)实现基于内容的真实路由器。

如果有意义,您可以使用Rebus的主题API来使用主题对此发布/订阅方案进行建模,以处理路由。如果您可以说您的数据消息属于某个类别,您的订阅者可以订阅这些类别,这是有道理的。

与“真实的”基于主题的排队系统相比,例如RabbitMQ,Rebus中的主题API非常粗糙。它不允许使用通配符(*)或任何类似的高级主题 - 主题只是您可以订阅的简单字符串,然后用作发布/订阅频道将事件路由到多个订阅者。

您可以在订阅者端使用它:

await bus.Advanced.Topics.Subscribe("department_a");

然后在出版商的最后:

var data = new Data(...);

await bus.Advanced.Topics.Publish("department_a", data);

如果没有删除它,您可以插入一个“真正的”基于内容的路由器,它只是您await bus.Send(eachDataMessage)的端点,而后者又将消息转发给相关订户。

根据您的要求,可以使用Rebus在两个级别完成。如果查看消息的标题就足够了,您应该将其实现为“传输消息转发器”,因为它会跳过反序列化并提供一个很好的API来简单地转发消息:

Configure.With(...)
    .Transport(t => t.UseMsmq("router"))
    .Routing(r => {
        r.AddTransportMessageForwarder(async transportMessage => {
            var headers = transportMessage.Headers;

            var subscribers = Decide(headers);

            return ForwardAction.ForwardTo(subscribers);
        });
    })
    .Start();

如果您需要查看实际消息,您应该只实现一个普通的消息处理程序,然后使用总线转发消息:

public class Router : IHandleMessages<Data>
{
    readonly IBus _bus;

    public Router(IBus bus)
    {
        _bus = bus;
    }   

    public async Task Handle(Data message)
    {
        var subscribers = Decide(message);

        foreach(var subscriber in subscribers)
        {
            await _bus.Advanced.TransportMessage.ForwardTo(subscriber);
        }
    }
}

自定义实现的路由器是最灵活的解决方案,因为您可以实现您喜欢的任何逻辑,但正如您所看到的那样稍微复杂一点。

(*)Rebus一般不允许使用通配符,尽管 直接将主题传递给RabbitMQ,如果你碰巧使用它作为传输,这意味着你实际上可以充分利用RabbitMQ(有关详细信息,请参阅this issue

答案 1 :(得分:0)

    static void Main()
    {

        using (var activator = new BuiltinHandlerActivator())
        {
            activator.Handle<Packet>(async (bus, packet) =>
            {
                string subscriber = "subscriberA";
                await bus.Advanced.TransportMessage.Forward(subscriber); 
            });

            Configure.With(activator)
                .Logging(l => l.ColoredConsole(minLevel: LogLevel.Warn))
                .Transport(t => t.UseMsmq("router"))
                .Start();

            for (int i = 0; i < 10; i++)
            {
                activator.Bus.SendLocal(
                    new Packet()
                    {
                        ID = i,
                        Content = "content" + i.ToString(),
                        Sent = false,
                    }).Wait();
            }
        }

        Console.ReadLine();
    }

答案 2 :(得分:0)

using (var trScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
   scope.EnlistRebus();
   Packet packet = ReadFromDB()
   activator.Bus.SendLocal(packet).Wait()
   scope.Complete()
}


activator.Handle<Packet>(async (bus, packet) =>
{
   string subscriber = "subscriberA";
   await bus.Advanced.TransportMessage.Forward(subscriber); 
});

答案 3 :(得分:0)

        using (var activator = new BuiltinHandlerActivator())
        {
            activator.Handle<Packet>(async message =>
            {
                string connectionString =
                    "Data Source=.;Initial Catalog=Rebus;User ID=sa;Password=123456";

                using (SqlConnection connection = new SqlConnection(connectionString))
                {
                    string queryString = @"INSERT INTO CLIENTPACKET(ID, CONTENT, SENT) VALUES(@id, @content, @sent)";
                    connection.Open();

                    using (SqlCommand command = new SqlCommand(queryString, connection))
                    {
                        command.Parameters.Add(new SqlParameter("@id", message.ID));
                        command.Parameters.Add(new SqlParameter("@content", message.Content));
                        command.Parameters.Add(new SqlParameter("@sent", message.Sent));

                        await command.ExecuteNonQueryAsync();
                    }
                }
            });


            Configure.With(activator)
                .Logging(l => l.ColoredConsole(minLevel: LogLevel.Warn))
                .Transport(t => t.UseMsmq(@"subscriberA"))
                .Routing(r => r.TypeBased().MapAssemblyOf<Packet>("router"))
                .Options(o =>
                {
                    TransactionOptions tranOp = new TransactionOptions();
                    tranOp.IsolationLevel = IsolationLevel.ReadCommitted;
                    o.HandleMessagesInsideTransactionScope(tranOp);

                    o.SetNumberOfWorkers(2);
                    o.SetMaxParallelism(2);
                })
                .Start();

            activator.Bus.Subscribe<Packet>().Wait();

            Console.WriteLine("Press ENTER to quit");
            Console.ReadLine();
        }