1

If we set up a Saga and immediately Publish(context => ...) then a message successfully hits the bus.

If however, we have something like

Initially(
  When(SomeCommand)
     .Then(context => { context.Instance.SomeField = 5 })
     .TransitionTo(SomeState)
     .Then(context => this.RaiseEvent(context.Instance, SomeEvent)));

During(SomeState,
  When(SomeEvent)
     // ConsumeContext is not available here
     .Publish(context => new SomeEventClass
        {
           Foo = context.Instance.SomeField
        })
     .Finalize());

The machine also never transitions to the Final state presumably because of the exception locating a ConsumeContext.

We have seen some references to passing a ConsumeContext as a parameter in Publish() however it's unclear as to which context this needs (Intellisense just makes reference to context1, context2, context3, etc).

Is there a way to use Publish() after RaiseEvent() has already been called? If not, is there a way to publish an event using some other mechanism?

MassTransit version is 5.1.5 and Automatonymous is 4.1.2


EDIT Based on Chris Patterson's answer here we have tried adding the below outside of any Initially or During

WhenEnter(NewState, state => state.Publish(context => 
    new EventClass { Foo = context.Instance.Foo }
  )
  .Finalize();

However it still doesn't publish anything and the state never transitions to Final. If we add a Then it also never hits this code block. There don't seem to be any exceptions occurring. We also tried using When(SomeState.Enter) and it also doesn't work.

Side question as maybe this will help with my understanding of why Publish and RaiseEvent don't seem to play nicely together - why does Publish need the ConsumeContext? Is it to locate the bus and bindings?

Daniel
  • 452
  • 3
  • 12
  • Before trying to look at this, could clarify what is the reason to raise an internal event after transitioning to the next state, which publishes one message and finalizes? Can't you publish and finalize right in that step before? – Alexey Zimarev Nov 05 '18 at 08:17
  • @AlexeyZimarev this is a massive simplification. The scenario is that we have a whole lot of events and actions that have to happen and we want to be able to retry at a particular state. Only when all the internal events have happened do we want to publish the final message. Let me know if that's not clear. – Daniel Nov 05 '18 at 08:38
  • We stuff like this too but we always use messages... – Alexey Zimarev Nov 05 '18 at 09:36
  • @AlexeyZimarev could you give an example? None of the services being co-ordinated publish messages and there's a lot of overhead (message classes, consumer classes) if we go down the route of using messages and not internal events. – Daniel Nov 05 '18 at 10:16

2 Answers2

1

The solution to this turned out to be using this:

.Then(context => context.Raise(SomeEvent))

instead of this:

.Then(context => this.RaiseEvent(context.Instance, SomeEvent))

It kinda makes sense now - the latter (as mentioned by Chris Patterson) creates a new EventContext while the former uses the given context. We didn't know that Raise was a method available on the passed in context.

Daniel
  • 452
  • 3
  • 12
0

You should be able to add

When(SomeState.Enter)

to your Initially section, and it will use the existing context. By creating a new EventContext with RaiseEvent, you aren't retaining the ConsumeContext.

You could also add WhenEnter(SomeState) outside of any Initially or During block.

Chris Patterson
  • 28,659
  • 3
  • 47
  • 59