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

Changed the behavior of InvokeAsync<T>() such that the T is NOT sent … #1028

Merged
merged 1 commit into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/guide/messaging/message-bus.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ case, Wolverine does enforce timeout conditions with a default of 5 seconds whic

## Request/Reply

::: warning
There was a breaking change in behavior for this functionality in Wolverine 3.0. The response type, the `T` in `InvokeAsync<T>()` is **not**
sent as a cascaded message if that type is the requested response type. You will have to explicitly send the response out through `IMessageBus.PublishAsync()`
to force that to be sent out instead of just being the response.
:::

Wolverine also has direct support for the [request/reply](https://www.enterpriseintegrationpatterns.com/RequestReply.html) pattern or really just mediating between your code and complex query handlers through
the `IMessageBus.InvokeAsync<T>()` API. To make that concrete, let's assume you want to request the results of a mathematical operation as shown below
in these message types and a corresponding message handler:
Expand Down Expand Up @@ -127,6 +133,10 @@ public async Task invoke_math_operations(IMessageBus bus)
Note that this API hides whether or not this operation is a local operation running on the same thread and invoking a local message handler or sending a message through to a remote
endpoint and waiting for the response. The same timeout mechanics and performance concerns apply to this operation as the `InvokeAsync()` method described in the previous section.

Note that if you execute the `Numbers` message from above with `InvokeAsync<Results>()`, the `Results` response will only be
returned as the response and will not be published as a message. This was a breaking change in Wolverine 3.0. We think (hope)
that this will be less confusing.

## Sending or Publishing Messages

[Publish/Subscribe](https://docs.microsoft.com/en-us/azure/architecture/patterns/publisher-subscriber) is a messaging pattern where the senders of messages do not need to specifically know what the specific subscribers are for a given message. In this case, some kind of middleware or infrastructure is responsible for either allowing subscribers to express interest in what messages they need to receive or apply routing rules to send the published messages to the right places. Wolverine's messaging support was largely built to support the publish/subscribe messaging pattern.
Expand Down
4 changes: 4 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ builder.Services.AddWolverineHttp();
<!-- endSnippet -->

Also for Wolverine.Http users, the `[Document]` attribute behavior in the Marten integration is now "required by default."

The behavior of `IMessageBus.InvokeAsync<T>(message)` changed in 3.0 such that the `T` response **is not also published as a
message** at the same time when the initial message is sent with request/response semantics. Wolverine has gone back and forth
in this behavior in its life, but at this point, the Wolverine thinks that this is the least confusing behavioral rule.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

namespace CoreTests.Acceptance;

public class local_invoke_also_publishes_the_return_value
public class local_invoke_does_not_publish_the_return_value
{
[Fact]
public async Task should_also_publish_the_return_value_when_invoking_locally()
public async Task should_not_publish_the_return_value_when_invoking_locally()
{
using var host = await Host.CreateDefaultBuilder()
.UseWolverine().StartAsync();
Expand All @@ -18,11 +18,7 @@ public async Task should_also_publish_the_return_value_when_invoking_locally()

response.Name.ShouldBe(name);

tracked.Sent.SingleMessage<CommandInvoked>()
.Name.ShouldBe(name);

tracked.Sent.SingleMessage<Message1>().Id.ShouldBe(response.Id);
tracked.Sent.SingleMessage<Message2>().Id.ShouldBe(response.Id);
tracked.Sent.MessagesOf<CommandInvoked>().Any().ShouldBeFalse();
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/Wolverine/Runtime/Handlers/Executor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public async Task<T> InvokeAsync<T>(object message, MessageBus bus, Cancellation
ReplyUri = TransportConstants.RepliesUri,
ReplyRequested = typeof(T).ToMessageTypeName(),
ResponseType = typeof(T),
TenantId = tenantId ?? bus.TenantId
TenantId = tenantId ?? bus.TenantId,
DoNotCascadeResponse = true
};

bus.TrackEnvelopeCorrelation(envelope, Activity.Current);
Expand Down
2 changes: 1 addition & 1 deletion src/Wolverine/Runtime/MessageContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ public async Task EnqueueCascadingAsync(object? message)
}

if (Envelope?.ResponseType != null && (message?.GetType() == Envelope.ResponseType ||
Envelope.ResponseType.IsAssignableFrom(message?.GetType())))
Envelope.ResponseType.IsInstanceOfType(message)))
{
Envelope.Response = message;

Expand Down
Loading