代码改变世界

译MassTransit 生产消息

2018-05-21 16:59  李明成  阅读(...)  评论(...编辑  收藏

生产消息

应用程序或服务可以使用两种不同的方法生产消息。可以使用Sead发送消息,也可以使用Publish发布消息。每个方法的行为是非常不同的,但是通过查看每个特定方法所涉及的消息类型,可以很容易理解。

当消息是 sent时,它使用DestinationAddress 传递交付到特定的端点。当消息是published,它不会发送到特定的端点,而是广播给订阅了该消息类型的任何消费者。对于这两个单独的行为, 我们描述作为命令发送的消息, 以及作为事件发布的消息。

在创建文档的消息契约部分时,将对此进行深入讨论。 

 发送命令

将命令发送到端点 需要 ISendEndpoint 引用,它可以从任何发送端点提供程序(支持ISendEndpointProvider的对象)中获得。应用程序应该始终使用与之最接近的对象来获取发送端点, 并且每次需要它时都应该这样做--应用程序不应缓存发送端点引用。例如,IBus 实例是一个发送端点提供程序,但它不应该被消费者用来获取ISendEndpoint.ConsumeContext 还可以提供发送端点,并且应该使用它,因为它更接近于消费者。

注意:这不能足够强调——总是从最接近的应用程序代码接口获得发送端点。使用会话、关联和发起标识符将消息流绑定在一起具有广泛的逻辑。通过跳过级别并在最接近的范围之外,可以丢失该信息,从而阻止有用的跟踪标识符被正确处理。

要从发送端点提供程序获得发送端点,请使用GetSendEndpoint()方法,如下所示。返回发送端点后,它就可以用于发送消息。

public async Task SendOrder(ISendEndpointProvider sendEndpointProvider)
{
    var endpoint = await sendEndpointProvider.GetSendEndpoint(_serviceAddress);

    await endpoint.Send(new SubmitOrder(...));
}

Send 方法有很多重载。因为MassTransit 是围绕filters和pipes构建的,所以pipes被用来定制发送的消息传递行为。还有一些有用的重载(通过扩展方法),使得 pipe 的构建更容易、更少噪音,等等。

通过接口发送

由于一般的建议是使用接口, 所以在不需要在下面创建消息类的情况下, 有一种方便的方法来初始化接口。虽然消息的版本化仍然需要支持多个接口的类,但下面显示了一种简单的发送接口消息的方法。

public interface SubmitOrder
{
    string OrderId { get; }
    DateTime OrderDate { get; }
    decimal OrderAmount { get; }
}

public async Task SendOrder(ISendEndpoint endpoint)
{
    await endpoint.Send<SubmitOrder>(new
    {
        OrderId = "27",
        OrderDate = DateTime.UtcNow,
        OrderAmount = 123.45m
    });
}

设置消息标题
有多种消息头可用以用于消息的相关性和跟踪。当发生故障时,也可以重写MassTransit 的一些默认行为。例如,当消费者抛出异常时,通常会发布故障。如果应用程序希望传递到特定地址的故障,则可以通过报头指定故障地址。如何做到这一点如下所示。

public interface SubmitOrder
{
    string OrderId { get; }
    DateTime OrderDate { get; }
    decimal OrderAmount { get; }
}

public async Task SendOrder(ISendEndpoint endpoint)
{
    await endpoint.Send<SubmitOrder>(new
    {
        OrderId = "27",
        OrderDate = DateTime.UtcNow,
        OrderAmount = 123.45m
    }, context => context.FaultAddress = new Uri("rabbitmq://localhost/order_faults"));
}

发布事件

消息的发布与消息的发送方式类似,但在这种情况下,使用单个IPublishEndpoint 。应用相同的端点规则,应该使用发布终结点的最接近实例。因此, 对消费者的 ConsumeContext, 以及 IBus 在消费者上下文之外发布的应用程序。

要发布消息,请参见下面的代码。 

public interface OrderSubmitted
{
    string OrderId { get; }
    DateTime OrderDate { get; }
}

public async Task NotifyOrderSubmitted(IPublishEndpoint publishEndpoint)
{
    await publishEndpoint.Publish<OrderSubmitted>(new
    {
        OrderId = "27",
        OrderDate = DateTime.UtcNow,
    });
}