Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Populate originator property on saga creation #457

Merged
merged 2 commits into from
Dec 2, 2022
Merged

Conversation

timbussmann
Copy link
Contributor

@timbussmann timbussmann commented Nov 29, 2022

Fixes #426 by ensuring that the Saga.Originator property is always assigned.

Note that this slightly deviates from NServiceBus.Core which doesn't populate the property when there is no ReplyTo header on the message starting a saga. Given this header is almost always sent when sending messages with NServiceBus, and the testable handler context has a default value for the context.ReplyTo property, using a default value seems valid. Not setting the value when the header is missing might also be a valid alternative to have a more accurate simulation though.


public Task Handle(SendReplyMessage message, IMessageHandlerContext context)
{
return ReplyToOriginator(context, new ReplyMessage { OriginatorAddress = Data.Originator });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting the values in the ReplyMessage is only useful for the asserts, and not required to make ReplyToOriginator work in this case, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I've added that to have a simple way to verify the value of Data.Originator outside the usage of ReplyToOriginator. That property is also publicly accessible.

@danielmarbach
Copy link
Contributor

Just a question out of curiousity. Why didn't you implement it this way?

Not setting the value when the header is missing might also be a valid alternative to have a more accurate simulation though.

Given the TestableSaga is about simulating saga behavior, that would sound like the more logical conclusion to me unless I misunderstood the design of TestableSaga (which is very likely since I wasn't involved)

@timbussmann
Copy link
Contributor Author

@danielmarbach there's an unfortunate duality of the replyToAddress. The NServiceBus code seems to retrieve the value from the headers but the pipeline context also contains a ReplyToAddress property (see https://github.com/Particular/NServiceBus/blob/master/src/NServiceBus.Core/IMessageProcessingContext.cs#L20) which is filled by core based on the replyTo header value when invoking the pipeline. But this property is also always set to a default value in the testable contexts so it's not reflecting the header values of the incoming message correctly.

Now it might seem perfectly valid for a user to configure the property on the context and expect that to influence the originator of the saga data (or other replyto related code) while simulating the core behavior it actually wouldn't. If better "simulation" is preferred, we shouldn't set that property value by default IMO (actually it looks like we should completely remove that property from the context).

Does that thought process make sense?

@danielmarbach
Copy link
Contributor

danielmarbach commented Nov 30, 2022

If I understood you correctly, then essentially the existence of the header is the "driver" for the property to be set. So in all cases when the header is not present, the property would be empty. So in that sense I guess if we would aim for simulation then the property should by default be empty unless such a header is around, would you agree under the assumption we strive for "simulating" the core behavior?

The question is though, I guess, do we want to simulate the core behavior?

@DavidBoike
Copy link
Member

We don't necessarily want to simulate core exactly. A scenario test is never going to comprise multiple endpoints. All the handlers get called right there in memory. So the mechanics of routing largely don't apply, yet have to just work as far as any important assertions that would be made.

@danielmarbach
Copy link
Contributor

I like that because that means having a default value on the Reply Address is good and better than having to go through "oh yeah when I set the header it will be there otherwise it won't" make the test setup way more complicated while all you potentially want to do is make sure some of your code that happens to read the reply address has a value around.

@timbussmann
Copy link
Contributor Author

Thanks for the discussion and thoughts. I've also looked at changing the default implementation of the ReplyToAddress property in the TestableMessageProcessingContext class to be something like this:

public string ReplyToAddress => MessageHeaders.TryGetValue(Headers.ReplyToAddress, out var replyAddress) ? replyAddress : "reply address";

this would also be perfectly valid IMO but it comes with the downside that there are possible scenarios where the property would actually be null in core, in case the header wouldn't be set on an incoming message (e.g. send-only endpoints or third party integration scenarios). With the approach mentioned above, this wouldn't be reproducible anymore. So I think there are two reasonable approaches:

  • Replicating core behavior and not setting the value, forcing users to provide the actual header value if they really depend on it (also a potentially breaking change for the testing library)
  • Keep the behavior suggested in this PR which provides some default value for more convenient testing but allows full control depending on what their code needs (using the headers directly or using the context property)

Happy to further discuss in case you feel we should change the approach.

@timbussmann timbussmann merged commit 3e8d5d2 into master Dec 2, 2022
@timbussmann timbussmann deleted the originator-saga branch December 2, 2022 16:32
timbussmann added a commit that referenced this pull request Dec 5, 2022
* add failing tests

* Set originator value when creating new saga
timbussmann added a commit that referenced this pull request Dec 5, 2022
* add failing tests

* Set originator value when creating new saga
timbussmann added a commit that referenced this pull request Dec 5, 2022
* add failing tests

* Set originator value when creating new saga
timbussmann added a commit that referenced this pull request Dec 6, 2022
* add failing tests

* Set originator value when creating new saga
timbussmann added a commit that referenced this pull request Dec 6, 2022
* add failing tests

* Set originator value when creating new saga
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Saga scenario testing framework can't handle ReplyToOriginator
3 participants