13.3 The parcel
Once an order is placed, the customer can follow its parcel. A parcel goes through states of its own, so it is a machine of its own, a child: a state of the checkout starts it and waits for it to end, and takes an outcome from how it ends, as it does from a run.
Our courier is a fake, as the payment provider is: a parcel is packed, in transit a minute later, and delivered a minute after that, by timers. A real courier would move it with events.
Shopfront.Core/Machines/Parcel/
├── ParcelMachine.cs
├── ParcelState.cs
├── ParcelTrigger.cs
├── ParcelContext.cs
└── Models/
└── ParcelResult.csShopfront.Core/Machines/Parcel/ParcelState.cs:
namespace Shopfront.Machines.Parcel;
public enum ParcelState
{
Packed,
InTransit,
Delivered,
}Shopfront.Core/Machines/Parcel/ParcelTrigger.cs:
namespace Shopfront.Machines.Parcel;
// The fake courier moves a parcel by timers alone; a real one would send events.
public enum ParcelTrigger
{
Scan,
}Shopfront.Core/Machines/Parcel/ParcelContext.cs:
namespace Shopfront.Machines.Parcel;
public sealed record ParcelContext;Shopfront.Core/Machines/Parcel/Models/ParcelResult.cs:
namespace Shopfront.Machines.Parcel.Models;
// What the checkout is told when the parcel ends: that it ended.
public sealed record ParcelResult;Shopfront.Core/Machines/Parcel/ParcelMachine.cs:
using System.Text.Json.Nodes;
using Trax.StateMachine;
using Trax.StateMachine.Persistence;
namespace Shopfront.Machines.Parcel;
public sealed class ParcelMachine : Machine<ParcelState, ParcelTrigger>
{
protected override void Configure(IMachineBuilder<ParcelState, ParcelTrigger> m)
{
m.Id("parcel").Version(1).StartsAt(ParcelState.Packed, () => new JsonObject());
m.In(ParcelState.Packed)
.Context<ParcelContext>()
.After(TimeSpan.FromMinutes(1))
.GoTo(ParcelState.InTransit);
m.In(ParcelState.InTransit)
.Context<ParcelContext>()
.After(TimeSpan.FromMinutes(1))
.GoTo(ParcelState.Delivered);
m.In(ParcelState.Delivered).Context<ParcelContext>().Ends();
}
}Ends() marks a state the machine ends in, which gives its parent OnDone. The parcel is not
served over GraphQL: only the checkout that spawned it reaches it. It belongs to the checkout's
owner, and it cannot be thrown away while the checkout waits on it.
SDK Reference
Invoke a train from a state | Invoked runs | Spawn a child machine | Machine