Skip to content

Commit 3ebdc28

Browse files
committed
refactor the IAsyncEnumerable out of the saga
BREAKING CHANGE: The ISaga.Evaluate no longer accepts an IAsyncEnumerable<IReason> as return value. Add reasons through the context.Result property instead.
1 parent 48d5d12 commit 3ebdc28

File tree

11 files changed

+31
-31
lines changed

11 files changed

+31
-31
lines changed

samples/ConsoleSample/Domain/TodoItemAddedSaga.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ namespace ConsoleSample.Domain;
77

88
public class TodoItemAddedSaga : ISaga<TodoItemCreated>
99
{
10-
public async IAsyncEnumerable<IReason> Evaluate(ISagaContext context, TodoItemCreated @event)
10+
public async Task Evaluate(ISagaContext context, TodoItemCreated @event)
1111
{
1212
await context.InvokeService(new NestedService());
13-
14-
yield break;
1513
}
1614
}

samples/Skyhop.Domain/AircraftContext/Sagas/OnAircraftChanged.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ namespace Skyhop.Domain.AircraftContext.Sagas;
1111

1212
internal class OnAircraftChanged : ISaga<AircraftSet>
1313
{
14-
public async IAsyncEnumerable<IReason> Evaluate(ISagaContext context, AircraftSet @event)
14+
public async Task Evaluate(ISagaContext context, AircraftSet @event)
1515
{
1616
var flight = await context.Factory
1717
.Instantiate<Flight>(context.AggregateId!)
1818
.Snapshot<FlightSnapshot>();
1919

2020
// There is no need to make a change as the flight is up to date with the latest state
21-
if (flight.AircraftId != @event.AircraftId) yield break;
21+
if (flight.AircraftId != @event.AircraftId) return;
2222

2323
var aircraft = await context.Factory
2424
.Instantiate<Aircraft>(@event.AircraftId)

samples/Skyhop.Domain/AircraftContext/Sagas/OnAircraftRemoved.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ namespace Skyhop.Domain.AircraftContext.Sagas;
1111

1212
public class OnAircraftRemoved : ISaga<AircraftRemoved>
1313
{
14-
public async IAsyncEnumerable<IReason> Evaluate(ISagaContext context, AircraftRemoved @event)
14+
public async Task Evaluate(ISagaContext context, AircraftRemoved @event)
1515
{
1616
var flight = await context.Factory
1717
.Instantiate<Flight>(context.AggregateId!)
1818
.Snapshot<FlightSnapshot>();
1919

2020
// No need to make a change; nothing to remove here.
21-
if (flight.AircraftId == @event.AircraftId) yield break;
21+
if (flight.AircraftId == @event.AircraftId) return;
2222

2323
var aircraft = await context.Factory
2424
.Instantiate<Aircraft>(@event.AircraftId)

samples/Skyhop.Domain/AircraftContext/Sagas/OnArrival.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Skyhop.Domain.AircraftContext.Sagas;
99

1010
internal class OnArrival : ISaga<ArrivalTimeSet>
1111
{
12-
public async IAsyncEnumerable<IReason> Evaluate(ISagaContext context, ArrivalTimeSet @event)
12+
public async Task Evaluate(ISagaContext context, ArrivalTimeSet @event)
1313
{
1414
var snapshot = await context.Factory
1515
.Instantiate<Flight>(context.AggregateId!)
@@ -23,7 +23,5 @@ public async IAsyncEnumerable<IReason> Evaluate(ISagaContext context, ArrivalTim
2323
context.AggregateId!,
2424
snapshot.DepartureTime,
2525
@event.ArrivalTime));
26-
27-
yield break;
2826
}
2927
}

samples/Skyhop.Domain/AircraftContext/Sagas/OnDeparture.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Skyhop.Domain.AircraftContext.Sagas;
99

1010
public class OnDeparture : ISaga<DepartureTimeSet>
1111
{
12-
public async IAsyncEnumerable<IReason> Evaluate(ISagaContext context, DepartureTimeSet @event)
12+
public async Task Evaluate(ISagaContext context, DepartureTimeSet @event)
1313
{
1414
var snapshot = await context.Factory
1515
.Instantiate<Flight>(context.AggregateId!)
@@ -23,7 +23,5 @@ public async IAsyncEnumerable<IReason> Evaluate(ISagaContext context, DepartureT
2323
context.AggregateId!,
2424
@event.DepartureTime,
2525
snapshot.ArrivalTime));
26-
27-
yield break;
2826
}
2927
}

src/Whaally.Domain.Abstractions/Saga/ISaga.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ namespace Whaally.Domain.Abstractions;
44

55
public interface ISaga
66
{
7-
public IAsyncEnumerable<IReason> Evaluate(ISagaContext context, IEvent @event);
7+
public Task Evaluate(ISagaContext context, IEvent @event);
88
}
99

1010
public interface ISaga<TEvent> : ISaga
1111
where TEvent : class, IEvent
1212
{
13-
IAsyncEnumerable<IReason> ISaga.Evaluate(ISagaContext context, IEvent @event)
13+
Task ISaga.Evaluate(ISagaContext context, IEvent @event)
1414
=> Evaluate(context, (TEvent)@event);
1515

16-
public IAsyncEnumerable<IReason> Evaluate(ISagaContext context, TEvent @event);
16+
public Task Evaluate(ISagaContext context, TEvent @event);
1717
}

src/Whaally.Domain.Abstractions/Saga/ISagaContext.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,25 @@ public interface ISagaContext : IContext
99
/// </summary>
1010
public IReadOnlyList<CommandEnvelope> Commands { get; }
1111

12+
/// <summary>
13+
/// Contains the failure or success reasons for this evaluation.
14+
/// </summary>
15+
public Result Result { get; }
16+
1217
/// <summary>
1318
/// Stages a command as the optimistic result of this saga.
1419
/// </summary>
1520
/// <param name="command">The command staged as a result of saga evaluation</param>
1621
public void StageCommands(
1722
string aggregateId,
1823
params ICommand[] command);
19-
24+
2025
/// <summary>
2126
/// Evaluates a service and stages the resulting commands as the optimistic result of this saga.
2227
/// </summary>
2328
/// <param name="service">The service to evaluate as part of the saga evaluation</param>
2429
/// <returns>A Result object indicating success or error states.</returns>
25-
public Task<IResultBase> InvokeService(IService service);
30+
public Task InvokeService(IService service);
2631

2732
/// <summary>
2833
/// The AggregateHandlerFactory provides access to AggregateHandler instances.

src/Whaally.Domain/DefaultEvaluationAgent.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,12 @@ public async Task<IResultBase> Invoke(ISaga saga, EventEnvelope eventEnvelope)
154154

155155
var result = new Result();
156156

157-
await foreach (var reason in saga.Evaluate(
158-
_contextFactory.CreateSagaContext(eventEnvelope.Metadata),
159-
eventEnvelope.Messages.Single()))
160-
{
161-
result.WithReason(reason);
162-
}
157+
var context = _contextFactory.CreateSagaContext(eventEnvelope.Metadata);
158+
await saga.Evaluate(
159+
context,
160+
eventEnvelope.Messages.Single());
161+
162+
result.WithReasons(context.Result.Reasons);
163163

164164
return result;
165165
}

src/Whaally.Domain/Saga/SagaContext.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public SagaContext(
2727
}
2828

2929
public string? AggregateId { get; init; }
30+
public Result Result { get; init; } = new();
3031
public string? TransactionId { get; init; }
3132
public ActivityContext? ParentContext { get; init; }
3233
public IReadOnlyDictionary<string, object> Attributes { get; init; }
@@ -66,7 +67,7 @@ public virtual void StageCommands(string aggregateId, params ICommand[] commands
6667
_envelopes.Add(aggregateId, envelope);
6768
}
6869

69-
public virtual async Task<IResultBase> InvokeService(IService service)
70+
public virtual async Task InvokeService(IService service)
7071
{
7172
var result = await _evaluationAgent.Evaluate(
7273
new ServiceEnvelope(
@@ -77,13 +78,13 @@ public virtual async Task<IResultBase> InvokeService(IService service)
7778
TransactionId = TransactionId
7879
}, service));
7980

80-
if (!result.IsSuccess) return result.ToResult();
81+
Result.WithReasons(result.Reasons);
82+
83+
if (!result.IsSuccess) return;
8184

8285
foreach (var envelope in result.Value)
8386
StageCommands(
8487
envelope.Metadata.AggregateId,
8588
envelope.Messages.ToArray());
86-
87-
return result.ToResult();
8889
}
8990
}

tests/Skyhop.Domain.Tests/AircraftContext/Sagas/OnDepartureTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ await AggregateFactory
5858
var @event = new DepartureTimeSet(DateTime.Now);
5959

6060
// Evaluate
61-
var result = saga.Evaluate(context, @event).ToBlockingEnumerable();
61+
await saga.Evaluate(context, @event);
6262

6363
// Assert
64-
result.Should().BeEmpty();
64+
context.Result.Reasons.Should().BeEmpty();
6565
Assert.Single(context.Commands);
6666
Assert.IsType<SetFlightInfo>(context.Commands.Single().Messages.Single());
6767
}

0 commit comments

Comments
 (0)