Skip to content

Commit

Permalink
Set nodes stateless (#27)
Browse files Browse the repository at this point in the history
* Set nodes stateless, future version exist both versions stateless & stateful

* Add some classes helper, tostring, equals...

* Add Saga Pattern example
  • Loading branch information
LHPiney authored Feb 4, 2022
1 parent e110c53 commit 8230eea
Show file tree
Hide file tree
Showing 40 changed files with 856 additions and 64 deletions.
4 changes: 3 additions & 1 deletion src/Magnett.Automation.Core/Contexts/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ private Context(IContextVault contextVault)
?? throw new ArgumentNullException(nameof(contextVault));
}

public void Store<TValue>(ContextField<TValue> field, TValue value)
public Context Store<TValue>(ContextField<TValue> field, TValue value)
{
_contextVault.Set(field, value);

return this;
}

public TValue Value<TValue>(ContextField<TValue> field)
Expand Down
5 changes: 5 additions & 0 deletions src/Magnett.Automation.Core/Magnett.Automation.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
<AssemblyVersion>0.50</AssemblyVersion>
<LangVersion>10</LangVersion>
<TargetFramework>net6.0</TargetFramework>
<PackageId>Magnett.Automation</PackageId>
</PropertyGroup>

<ItemGroup>
<Folder Include="WorkFlows\Implementations\Nodes" />
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions src/Magnett.Automation.Core/StateMachines/IMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ public interface IMachine

IMachine Dispatch(Enumeration action);
IMachine Dispatch(string actionName);
public bool Equals(CommonNamedKey obj);
public bool Equals(Enumeration obj);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ namespace Magnett.Automation.Core.StateMachines.Implementations
{
public class Machine : IMachine
{
private readonly IMachineDefinition _definition;
protected readonly IMachineDefinition _definition;

private Machine(IMachineDefinition definition)
protected Machine(IMachineDefinition definition)
{
_definition = definition
?? throw new ArgumentNullException(nameof(definition));
Expand Down Expand Up @@ -47,9 +47,20 @@ public IMachine Dispatch(string actionName)
}

public IState State { get; private set; }

public bool Equals(CommonNamedKey obj)
{
return State.Key.Equals(obj);
}

public bool Equals(Enumeration obj)
{
return State.Key.Equals(obj);
}

#endregion



public static IMachine Create(IMachineDefinition definition)
{
return new Machine(definition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[assembly: InternalsVisibleTo("Magnett.Automation.Core.UnitTest")]
namespace Magnett.Automation.Core.StateMachines.Implementations
{
internal class State : IState
internal class State : IState
{
private readonly TransitionList _transitionList;

Expand Down Expand Up @@ -41,7 +41,12 @@ public bool IsFinalState()
}

#endregion


public override string ToString()
{
return Key.Name;
}

public static State Create(string name, TransitionList transitionList)
{
return new(name, transitionList);
Expand Down
3 changes: 3 additions & 0 deletions src/Magnett.Automation.Core/WorkFlows/IFlow.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using System;
using System.Threading.Tasks;
using Magnett.Automation.Core.Contexts;
using Magnett.Automation.Core.WorkFlows.Implementations;

namespace Magnett.Automation.Core.WorkFlows
{
public interface IFlow
{
Guid Id { get; }

Context Context { get; }

Task<NodeExit> Run();
}
Expand Down
6 changes: 4 additions & 2 deletions src/Magnett.Automation.Core/WorkFlows/INode.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
namespace Magnett.Automation.Core.WorkFlows
using Magnett.Automation.Core.Contexts;

namespace Magnett.Automation.Core.WorkFlows
{
public interface INode : INodeBase
{
public NodeExit Execute();
public NodeExit Execute(Context context);
}
}
3 changes: 2 additions & 1 deletion src/Magnett.Automation.Core/WorkFlows/INodeAsync.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System.Threading.Tasks;
using Magnett.Automation.Core.Contexts;

namespace Magnett.Automation.Core.WorkFlows
{
public interface INodeAsync : INodeBase
{
Task<NodeExit> Execute();
Task<NodeExit> Execute(Context context);
}
}
2 changes: 0 additions & 2 deletions src/Magnett.Automation.Core/WorkFlows/INodeBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ namespace Magnett.Automation.Core.WorkFlows
public interface INodeBase
{
public CommonNamedKey Key { get; }
public bool IsInit { get; }
public string Name => Key?.Name;
void Init(Context flowContext);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Magnett.Automation.Core.Contexts;

namespace Magnett.Automation.Core.WorkFlows.Implementations
{
Expand All @@ -16,7 +17,8 @@ private Flow(IFlowRunner flowRunner)
#region IFlow

public Guid Id { get; } = Guid.NewGuid();

public Context Context => _flowRunner.FlowContext;

public async Task<NodeExit> Run()
{
return await _flowRunner.Start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ protected FlowRunnerBase(IFlowDefinition definition, Context context)

protected async Task<NodeExit> ExecuteNode(INodeBase node)
{
if (!node.IsInit) node.Init(FlowContext);

return node switch
{
INodeAsync nodeAsync => await nodeAsync.Execute(),
INode nodeSync => await Task.Run(() => nodeSync.Execute()),
INodeAsync nodeAsync => await nodeAsync.Execute(FlowContext),
INode nodeSync => await Task.Run(() => nodeSync.Execute(FlowContext)),
{ } => throw new ArgumentException("Not a valid node"),
null => throw new ArgumentNullException(nameof(node))
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Magnett.Automation.Core.Commons;
using Magnett.Automation.Core.Contexts;

namespace Magnett.Automation.Core.WorkFlows.Implementations
{
Expand All @@ -14,6 +15,6 @@ protected Node(CommonNamedKey key) : base(key)

}

public abstract NodeExit Execute();
public abstract NodeExit Execute(Context context);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using Magnett.Automation.Core.Contexts;

namespace Magnett.Automation.Core.WorkFlows.Implementations
{
Expand All @@ -8,6 +9,6 @@ protected NodeAsync(string name) : base(name)
{
}

public abstract Task<NodeExit> Execute();
public abstract Task<NodeExit> Execute(Context context);
}
}
10 changes: 0 additions & 10 deletions src/Magnett.Automation.Core/WorkFlows/Implementations/NodeBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ namespace Magnett.Automation.Core.WorkFlows.Implementations
{
public abstract class NodeBase
{
protected Context GlobalContext { get; private set; }
public CommonNamedKey Key { get; }
public bool IsInit { get; private set; }

protected NodeBase(string name) : this(CommonNamedKey.Create(name))
{
Expand All @@ -20,13 +18,5 @@ protected NodeBase(CommonNamedKey key)
Key = key
?? throw new ArgumentNullException(nameof(key));
}

public virtual void Init(Context globalContext)
{
GlobalContext = globalContext
?? throw new ArgumentNullException(nameof(globalContext));

IsInit = true;
}
}
}
8 changes: 8 additions & 0 deletions src/Magnett.Automation.Core/WorkFlows/NodeExit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,13 @@ public static NodeExit Create(
{
return new NodeExit(code, isError, data);
}

public static NodeExit Create(
Enumeration code,
bool isError = false,
string data = null)
{
return new NodeExit(code?.Name, isError, data);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Magnett.Automation.Core.IntegrationTest.WorkFlows.SagaPattern.Definitions.States;

namespace Magnett.Automation.Core.IntegrationTest.WorkFlows.SagaPattern.Definitions.Entities;

public class Order
{
public OrderState State { get; }
public Guid Id { get; }
public double Amount { get; }
public string Description { get; }

private Order(double amount, string description)
{
Id = Guid.NewGuid();
Amount = amount;
Description = description;

State = OrderState.Create();
}

public static Order Create(double amount, string description)
{
return new Order(amount, description);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using Magnett.Automation.Core.IntegrationTest.WorkFlows.SagaPattern.Definitions.States;
using Magnett.Automation.Core.StateMachines;

namespace Magnett.Automation.Core.IntegrationTest.WorkFlows.SagaPattern.Definitions.Entities;

public class Payment
{
public Guid Id { get; }
public double Amount { get; }
public PaymentState State { get; }

private Payment(double amount)
{
Id = Guid.NewGuid();
Amount = amount;

State = PaymentState.Create();
}

public static Payment Create(double amount)
{
return new Payment(amount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Magnett.Automation.Core.Commons;

namespace Magnett.Automation.Core.IntegrationTest.WorkFlows.SagaPattern.Definitions
{
internal class NodeName : CommonNamedKey
{
public static readonly NodeName CreateOrder = new NodeName(nameof(CreateOrder));
public static readonly NodeName ConfirmOrder = new NodeName(nameof(ConfirmOrder));
public static readonly NodeName CancelOrder = new NodeName(nameof(CancelOrder));

public static readonly NodeName PreAuthorizePayment = new NodeName(nameof(PreAuthorizePayment));
public static readonly NodeName ConfirmPayment = new NodeName(nameof(ConfirmPayment));
public static readonly NodeName CancelPayment = new NodeName(nameof(CancelPayment));

private NodeName(string name) : base(name)
{

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Threading.Tasks;
using Magnett.Automation.Core.Commons;
using Magnett.Automation.Core.Contexts;
using Magnett.Automation.Core.IntegrationTest.WorkFlows.SagaPattern.Definitions.Entities;
using Magnett.Automation.Core.IntegrationTest.WorkFlows.SagaPattern.Definitions.States;
using Magnett.Automation.Core.WorkFlows;
using Magnett.Automation.Core.WorkFlows.Implementations;

namespace Magnett.Automation.Core.IntegrationTest.WorkFlows.SagaPattern.Definitions.Nodes;

/// <summary>
/// Rollback Order operation and cancel process
/// </summary>
public class CancelOrder : NodeAsync
{
private CancelOrder(string name) : base(name)
{
}

private readonly ContextField<Order> _orderField = ContextField<Order>.Create("Order");

#region ExitCodes

public class ExitCode : Enumeration
{
public static readonly ExitCode Done = new ExitCode(1, nameof(Done));

private ExitCode(int id, string name) : base(id, name)
{
}
}

#endregion

public override async Task<NodeExit> Execute(Context context)
{
var order = context.Value(_orderField);

order.State.Dispatch(OrderStateDefinition.Action.Cancel);

await Task.Delay(1000);

return NodeExit.Create(
ExitCode.Done,
true,
$"Order cancelled id [{order.Id}] [{order.State}]");
}

public static CancelOrder Create(CommonNamedKey nodeName)
{
return new CancelOrder(nodeName?.Name);
}
}
Loading

0 comments on commit 8230eea

Please sign in to comment.