Tutorial

1.6 The train

Trains/PlaceOrder/IPlaceOrderTrain.cs:

using Trax.Effect.Services.ServiceTrain;
 
namespace Shopfront.Trains.PlaceOrder;
 
public interface IPlaceOrderTrain : IServiceTrain<PlaceOrderInput, PlaceOrderOutput>;

Trains/PlaceOrder/PlaceOrderTrain.cs:

using Shopfront.Trains.PlaceOrder.Junctions;
using Trax.Core.Functional;
using Trax.Effect.Services.ServiceTrain;
 
namespace Shopfront.Trains.PlaceOrder;
 
public class PlaceOrderTrain : ServiceTrain<PlaceOrderInput, PlaceOrderOutput>, IPlaceOrderTrain
{
    protected override Task<Either<Exception, PlaceOrderOutput>> Junctions() =>
        Chain<PriceCartJunction>()
            .Chain<ReserveStockJunction>()
            .Chain<TakePaymentJunction>()
            .Chain<ConfirmOrderJunction>()
            .Resolve();
}

The train is only the order of its junctions. Nothing here passes a value from one junction to the next: the train carries a store called Memory, which holds the input when the train starts and each junction's output as it finishes, one value per type. Every junction takes its input from there. That is how TakePaymentJunction gets the PlaceOrderInput even though the junction just before it made a StockReservation. One value per type also means a junction that returns a type already in Memory replaces the value there, which is why each junction here returns a type of its own (Memory).

Nothing reads the StockReservation yet. In chapter 3 the payment starts failing, and TakePaymentJunction takes the reservation too, to give the stock back before the order stops.

IPlaceOrderTrain is how the rest of the application asks for the train, and its full name is the name Trax records each run under.

SDK Reference

Junctions | Chain | Run / RunEither | TrainException | AddTrax / AddEffects | UseInMemory | SaveTrainParameters | AddMediator


Next: 1.7 Run it