0

The documentation for MassTransit Event Hub Riders recommends using an IEventHubProducerProvider (part of the MassTransit.EventHub nuget package) to send messages to an EventHub. However, most MassTransit documentation suggests that when publishing a message from a message consumer, the developer should use "the closest instance of the publish endpoint" to publish the message. In my application, I want to host the same MassTransitStateMachine in two different contexts:

  1. Where it is using an in-memory bus and all messages between it and other producers and consumers are part of the same process.
  2. Where it is using an Event Hub rider to receive and publish messages.

In my mind, the cleanest implementation of this would defer all configuration of where a published message goes to the Bus Configuration, and not take a dependency on MassTransit.EventHub in the message consumers at all. This led me to ask the question, "can I publish messages with a ConsumeContext and have the message end up on the EventHub? Or do I have to rely on the IEventHubProducerProvider (or maybe provide my own in-memory implementation of this that uses the ConsumeContext under the hood?)"

Any guidance on how to do this would be appreciated. It seems like the IEventHubProducerProvider is at odds with the Producers guidance, but more likely I just don't understand something.

user483679
  • 665
  • 1
  • 7
  • 21

1 Answers1

2

If you're producing messages to Event Hub from within a state machine, there are Produce extension methods which can be used. They have the same signature as the PublishAsync extension methods, but direct the messages to Event Hub.

For example (taken from the unit tests):

Initially(
    When(Started)
        .Then(context => context.Instance.Key = context.Data.TestKey)
        .Produce(x => Configuration.EventHubName, x => x.Init<EventHubMessage>(new {Text = $"Key: {x.Data.TestKey}"}))
        .TransitionTo(Active));
Chris Patterson
  • 28,659
  • 3
  • 47
  • 59
  • I did not know about the `Produce` extension methods! They seem close to/maybe exactly what I want. If I register the same MassTransitStateMachine in a different application in which there is no EventHub Rider defined (i.e. all producers/consumers connect to the same in-memory bus on the same machine, a transport that does not define the concept of EventHubName aka "topic name"), does calling Produce like that just send the message over the bus anyways or is that going to cause other problems? – user483679 Jan 18 '21 at 16:25
  • It will likely cause problems if there isn't an event hub producer. If you want to do that, you'd likely need to stub out the Event Hub objects required to avoid exceptions when there is no Event Hub rider. – Chris Patterson Jan 18 '21 at 17:23
  • Looking closer, it seems the `Produce` methods depend on an `EventActivityBinder` rather than the `BehaviorContext` available in Custom Activities. There is a little bit of stateful logic (for each value in a list on the Saga instance state, send a copy of the received message with the correlationId set to the current iteration value) this service needs to implement, and it seems there is no way to "iterate saga instance state collection and Produce for each" within Automatonymous now. Can `Produce` be used with `BehaviorContext` somehow? – user483679 Jan 18 '21 at 21:33
  • In that case, you'd need to create your own activity for the state machine with a dependency on the producer, and put your logic in that activity. There are many examples of state machine activities, you can even look at the actual [produce activity](https://github.com/MassTransit/MassTransit/blob/develop/src/Transports/MassTransit.KafkaIntegration/Activities/ProduceActivity.cs) – Chris Patterson Jan 19 '21 at 04:30
  • 1
    Thanks... that's what I've landed on. I created an abstracted "produce message to topic" event publisher w/different implementations (one for EventHub transport and one for in-memory), and then created custom activity with a dependency on the abstracted event publisher. The activity can inspect the abstracted event publisher and decide to put its message in it or in the activity's own BehaviorContext Publish method (In-Memory transport, other non-rider channels to publish messages to). – user483679 Jan 19 '21 at 05:34