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
5 changes: 3 additions & 2 deletions docs/guide/handlers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,9 @@ would use those values.
Pay attention to this section if you are trying to utilize a "Modular Monolith" architecture.
:::

::: warning
The `Separated` setting is ignored by `Saga` handlers
::: info
The `Separated` setting is useful even with `Saga` handlers as of Wolverine 5.10, but ignored
in previous versions.
:::

Let's say that you want to take more than one action on a message type published in or to your
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Diagnostics;
using JasperFx.Core;
using Microsoft.Extensions.Hosting;
using Wolverine.Attributes;
using Wolverine.Tracking;
using Xunit;

namespace CoreTests.Persistence.Sagas;

public class using_a_saga_with_separated_behavior_mode
{
[Fact]
public async Task able_to_use_separated_behaviors_with_sagas()
{
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
{
opts.Discovery.DisableConventionalDiscovery()
.IncludeType(typeof(TrackedThing))
.IncludeType(typeof(OtherThingUpdatedHandler));

opts.MultipleHandlerBehavior = MultipleHandlerBehavior.Separated;
}).StartAsync();

var id = Guid.NewGuid();

await host.InvokeMessageAndWaitAsync(new StartTracking(id));

var tracked = await host.SendMessageAndWaitAsync(new ThingUpdated(id));
var envelopes = tracked.Executed.Envelopes().Where(x => x.Message is ThingUpdated).ToArray();
envelopes.Length.ShouldBe(2);

envelopes.Any(x => x.Destination == new Uri("local://coretests.persistence.sagas.trackedthing/")).ShouldBeTrue();
envelopes.Any(x => x.Destination == new Uri("local://coretests.persistence.sagas.otherthingupdatedhandler/")).ShouldBeTrue();
}
}

public record StartTracking(Guid Id);

public record ThingUpdated(Guid Id);

public class TrackedThing : Saga
{
public Guid Id { get; set; }

public int Updates { get; set; }

public static TrackedThing Start(StartTracking cmd) => new TrackedThing { Id = cmd.Id };

public void Handle(ThingUpdated updated, Envelope envelope)
{
Updates++;
Debug.WriteLine(envelope.Destination);
}
}

[WolverineIgnore]
public static class OtherThingUpdatedHandler
{
public static void Handle(ThingUpdated updated)
{
Debug.WriteLine("Got updated for " + updated.Id);
}
}
26 changes: 21 additions & 5 deletions src/Wolverine/Persistence/Sagas/SagaChain.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Diagnostics;
using JasperFx;
using JasperFx.CodeGeneration;
using JasperFx.CodeGeneration.Frames;
using JasperFx.CodeGeneration.Model;
using JasperFx.Core;
using JasperFx.Core.Reflection;
using System.Reflection;
using Wolverine.Configuration;
using Wolverine.Logging;
using Wolverine.Runtime.Handlers;

Expand Down Expand Up @@ -51,6 +53,25 @@ public SagaChain(WolverineOptions options, IGrouping<Type, HandlerCall> grouping
}
}

public SagaChain(HandlerCall handlerCall, HandlerGraph handlerGraph, Endpoint[] endpoints) : base(handlerCall, handlerGraph)
{
foreach (var endpoint in endpoints) RegisterEndpoint(endpoint);

var saga = handlerCall;
SagaType = saga.HandlerType;
SagaMethodInfo = saga.Method;

Handlers.Add(handlerCall);

SagaIdMember = DetermineSagaIdMember(MessageType, SagaType, saga.Method);

// Automatically audit the saga id
if (SagaIdMember != null && AuditedMembers.All(x => x.Member != SagaIdMember))
{
AuditedMembers.Add(new AuditedMember(SagaIdMember, SagaIdMember.Name, SagaIdMember.Name));
}
}

public override bool TryInferMessageIdentity(out PropertyInfo? property)
{
property = SagaIdMember as PropertyInfo;
Expand All @@ -62,11 +83,6 @@ protected override void validateAgainstInvalidSagaMethods(IGrouping<Type, Handle
// Nothing
}

protected override void tryAssignStickyEndpoints(HandlerCall handlerCall, WolverineOptions options)
{
// nope, don't do this with saga chains
}

public Type SagaType { get; }

public MethodInfo? SagaMethodInfo { get; set; }
Expand Down
7 changes: 4 additions & 3 deletions src/Wolverine/Runtime/Handlers/HandlerChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public HandlerChain(Type messageType, HandlerGraph parent)
applyAuditAttributes(messageType);
}

private HandlerChain(MethodCall call, HandlerGraph parent) : this(call.Method.MessageType()!, parent)
protected HandlerChain(MethodCall call, HandlerGraph parent) : this(call.Method.MessageType()!, parent)
{
Handlers.Add(call);
}
Expand Down Expand Up @@ -284,15 +284,16 @@ bool ICodeFile.AttachTypesSynchronously(GenerationRules rules, Assembly assembly
/// </summary>
public FailureRuleCollection Failures { get; } = new();

protected virtual void tryAssignStickyEndpoints(HandlerCall handlerCall, WolverineOptions options)
protected void tryAssignStickyEndpoints(HandlerCall handlerCall, WolverineOptions options)
{
var endpoints = findStickyEndpoints(handlerCall, options).Distinct().ToArray();
if (endpoints.Any())
{
foreach (var stub in endpoints.OfType<StubEndpoint>())
stub.Subscriptions.Add(Subscription.ForType(MessageType));

var chain = new HandlerChain(handlerCall, options.HandlerGraph, endpoints);
var chain = handlerCall.HandlerType.CanBeCastTo<Saga>() ? new SagaChain(handlerCall,
options.HandlerGraph, endpoints) : new HandlerChain(handlerCall, options.HandlerGraph, endpoints);

Handlers.Remove(handlerCall);

Expand Down
1 change: 1 addition & 0 deletions src/Wolverine/Runtime/Handlers/HandlerGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ IEnumerable<HandlerChain> explodeChains(HandlerChain chain)

// This lovely thing was brought to you by https://github.com/JasperFx/wolverine/issues/2004
var duplicateTypeNames = allChains
.Where(x => x.Handlers.Any()) // filter out the parent, placeholder HandlerChain for separated handlers
.GroupBy(x => x.TypeName)
.Where(x => x.Count() > 1)
.ToArray();
Expand Down
Loading