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

flag to disable all remote usage of InvokeAsync() to protect teams fr… #1196

Merged
merged 1 commit into from
Dec 31, 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
2 changes: 1 addition & 1 deletion docs/guide/handlers/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ public class WrapWithSimple : IHandlerPolicy
}
}
```
<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Testing/CoreTests/BootstrappingSamples.cs#L23-L33' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_wrapwithsimple' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Testing/CoreTests/BootstrappingSamples.cs#L39-L49' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_wrapwithsimple' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Then register your custom `IHandlerPolicy` with a Wolverine application like this:
Expand Down
23 changes: 23 additions & 0 deletions docs/guide/messaging/message-bus.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,29 @@ public class CreateItemCommandHandler
<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Persistence/MartenTests/Bugs/Bug_305_invoke_async_with_return_not_publishing_with_tuple_return_value.cs#L39-L60' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using_alwayspublishresponse' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Disabling Remote Request/Reply

When you call `IMessageBus.InvokeAsync()` or `IMessageBus.InvokeAsync<T>()`, depending on whether Wolverine has a local message
handler for the message type or has a configured subscription rule for the message type, Wolverine *might* be making a remote
call through external messaging transports to execute that message. It's a perfectly valid use case to do the remote
invocation, but if you don't want this to ever happen or catch a team by surprise when an operation fails, you can completely
disable all remote request/reply usage through `InvokeAsync()` by changing this setting:

<!-- snippet: sample_disabling_remote_invocation -->
<a id='snippet-sample_disabling_remote_invocation'></a>
```cs
using var host = Host.CreateDefaultBuilder()
.UseWolverine(opts =>
{
// This will disallow Wolverine from making remote calls
// through IMessageBus.InvokeAsync() or InvokeAsync<T>()
// Instead, Wolverine will throw an InvalidOperationException
opts.EnableRemoteInvocation = false;
}).StartAsync();
```
<sup><a href='https://github.com/JasperFx/wolverine/blob/main/src/Testing/CoreTests/BootstrappingSamples.cs#L24-L35' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_disabling_remote_invocation' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## 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
16 changes: 16 additions & 0 deletions src/Testing/CoreTests/BootstrappingSamples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ public static async Task AppWithHandlerPolicy()

#endregion
}

public static async Task DisableRemoteInvocation()
{
#region sample_disabling_remote_invocation

using var host = Host.CreateDefaultBuilder()
.UseWolverine(opts =>
{
// This will disallow Wolverine from making remote calls
// through IMessageBus.InvokeAsync() or InvokeAsync<T>()
// Instead, Wolverine will throw an InvalidOperationException
opts.EnableRemoteInvocation = false;
}).StartAsync();

#endregion
}
}

#region sample_WrapWithSimple
Expand Down
6 changes: 6 additions & 0 deletions src/Testing/CoreTests/WolverineOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@ public void find_named_transport()
transport2.ShouldNotBeSameAs(transport1);
}

[Fact]
public void enable_remote_invocation_is_true_by_default()
{
new WolverineOptions().EnableRemoteInvocation.ShouldBeTrue();
}

public interface IFoo;

public class Foo : IFoo;
Expand Down
9 changes: 9 additions & 0 deletions src/Wolverine/Runtime/Routing/MessageRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class MessageRoute : IMessageRoute, IMessageInvoker
ImHashMap<Type, IList<IEnvelopeRule>>.Empty;

private readonly IReplyTracker _replyTracker;
private readonly Endpoint _endpoint;

public MessageRoute(Type messageType, Endpoint endpoint, IReplyTracker replies)
{
Expand All @@ -42,6 +43,8 @@ public MessageRoute(Type messageType, Endpoint endpoint, IReplyTracker replies)
Rules.AddRange(RulesForMessageType(messageType));

MessageType = messageType;

_endpoint = endpoint;
}

public Type MessageType { get; }
Expand Down Expand Up @@ -120,6 +123,12 @@ public async Task<T> InvokeAsync<T>(object message, MessageBus bus,
throw new ArgumentNullException(nameof(message));
}

if (!bus.Runtime.Options.EnableRemoteInvocation)
{
throw new InvalidOperationException(
$"Remote invocation is disabled in this application through the {nameof(WolverineOptions)}.{nameof(WolverineOptions.EnableRemoteInvocation)} value. Cannot invoke at requested endpoint {_endpoint.Uri}");
}

bus.Runtime.RegisterMessageType(typeof(T));

timeout ??= 5.Seconds();
Expand Down
7 changes: 7 additions & 0 deletions src/Wolverine/WolverineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ public WolverineOptions(string? assemblyName)
internal LocalTransport LocalRouting => Transports.GetOrCreate<LocalTransport>();
internal bool LocalRoutingConventionDisabled { get; set; }

/// <summary>
/// Should remote usages of IMessageBus.InvokeAsync() or IMessageBus.InvokeAsync<T>()
/// that ultimately use an external transport be enabled? Default is true, but you
/// may want to disable this to avoid surprise network round trips
/// </summary>
public bool EnableRemoteInvocation { get; set; } = true;

private void deriveServiceName()
{
if (GetType() == typeof(WolverineOptions))
Expand Down
Loading