Skip to content
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
53 changes: 52 additions & 1 deletion src/Testing/CoreTests/Acceptance/remote_invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public async Task InitializeAsync()

opts.PublishMessage<Request4>().ToPort(_receiver1Port);
opts.PublishMessage<Request4>().ToPort(_receiver2Port);

opts.PublishMessage<AlwaysPublishRequest>().ToPort(_receiver1Port);

opts.EnableAutomaticFailureAcks = true;
}).StartAsync();
}
Expand Down Expand Up @@ -400,6 +401,27 @@ public async Task sad_path_send_and_wait_with_no_subscription()

await Should.ThrowAsync<IndeterminateRoutesException>(() => publisher.InvokeAsync(new RequestWithNoHandler()));
}

[Fact]
public async Task always_publish_response_should_also_publish_on_remote_request_reply()
{
AlwaysPublishResponseReceivedHandler.Received = new TaskCompletionSource<bool>();

var (session, response) = await _sender.TrackActivity()
.AlsoTrack(_receiver1)
.Timeout(10.Seconds())
.WaitForMessageToBeReceivedAt<AlwaysPublishResponse>(_receiver1)
.InvokeAndWaitAsync<AlwaysPublishResponse>(new AlwaysPublishRequest { Name = "test" });

// The response should have been returned to the sender via request/reply
response.ShouldNotBeNull();
response.Name.ShouldBe("test");

// The response should ALSO have been published as a cascading message
// and handled by AlwaysPublishResponseReceivedHandler on the receiver
var handled = await AlwaysPublishResponseReceivedHandler.Received.Task.WaitAsync(10.Seconds());
handled.ShouldBeTrue();
}
}

public class Request1
Expand Down Expand Up @@ -434,6 +456,35 @@ public class Response3
public string Name { get; set; }
}

public class AlwaysPublishRequest
{
public string Name { get; set; }
}

public class AlwaysPublishResponse
{
public string Name { get; set; }
}

public static class AlwaysPublishResponseReceivedHandler
{
public static TaskCompletionSource<bool> Received { get; set; } = new();

public static void Handle(AlwaysPublishResponse response)
{
Received.TrySetResult(true);
}
}

public static class AlwaysPublishRequestHandler
{
[AlwaysPublishResponse]
public static AlwaysPublishResponse Handle(AlwaysPublishRequest request)
{
return new AlwaysPublishResponse { Name = request.Name };
}
}

public class RequestHandler
{
[MessageTimeout(3)]
Expand Down
1 change: 1 addition & 0 deletions src/Wolverine/Attributes/AlwaysPublishResponseAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@

internal class AlwaysPublishResponseFrame : SyncFrame
{
private Variable _envelope;

Check warning on line 23 in src/Wolverine/Attributes/AlwaysPublishResponseAttribute.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_envelope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Wolverine/Attributes/AlwaysPublishResponseAttribute.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_envelope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Wolverine/Attributes/AlwaysPublishResponseAttribute.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_envelope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Wolverine/Attributes/AlwaysPublishResponseAttribute.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_envelope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Wolverine/Attributes/AlwaysPublishResponseAttribute.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_envelope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Wolverine/Attributes/AlwaysPublishResponseAttribute.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_envelope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 23 in src/Wolverine/Attributes/AlwaysPublishResponseAttribute.cs

View workflow job for this annotation

GitHub Actions / test

Non-nullable field '_envelope' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
{
writer.WriteComment("Always publish the response as a message due to the [AlwaysPublishResponse] usage");
writer.WriteLine($"{_envelope.Usage}.{nameof(Envelope.DoNotCascadeResponse)} = false;");
writer.WriteLine($"{_envelope.Usage}.{nameof(Envelope.AlwaysPublishResponse)} = true;");
Next?.GenerateCode(method, writer);
}

Expand Down
9 changes: 9 additions & 0 deletions src/Wolverine/Envelope.Internals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ internal Envelope(object message, IMessageSerializer writer)
[JsonIgnore]
public bool DoNotCascadeResponse { get; set; }

/// <summary>
/// Used by the [AlwaysPublishResponse] attribute to explicitly signal
/// that the response should be published as a cascading message in addition
/// to being sent back via request/reply. This flag works for both in-process
/// and remote request/reply scenarios.
/// </summary>
[JsonIgnore]
public bool AlwaysPublishResponse { get; set; }

/// <summary>
/// Status according to the message persistence
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/Wolverine/Runtime/MessageContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,13 @@ public async Task EnqueueCascadingAsync(object? message)
if (Envelope?.ReplyUri != null && message.GetType().ToMessageTypeName() == Envelope.ReplyRequested)
{
await EndpointFor(Envelope.ReplyUri!).SendAsync(message, new DeliveryOptions { IsResponse = true });

// If [AlwaysPublishResponse] was used, also publish as a cascading message
if (Envelope.AlwaysPublishResponse)
{
await PublishAsync(message);
}

return;
}

Expand Down
Loading