How-to guide

Move work around a chain into junctions

A train's chain is declared in Junctions() and nowhere else (see why), so work that would otherwise sit above or around the chain goes into the chain. This page says where each kind of work goes.

Find the place for the work

What you needWhere it goes
Logic before or after the chainA junction at the head or the tail of it
Extra objects in MemoryA junction whose return value is that object, or AddServices<IService>(value) or Extract<TIn, TOut>(value) in the chain
Returning a failureA junction that throws; the chain turns it into Left
Async setupA junction, which is async already
Merging a nested train's resultA junction that calls ITrainBus and returns the merged value
Reading the input to decide what runsA junction that takes the input, or a Switch on a decision about it; Junctions() cannot read TrainInput

Run a nested train from a junction

  1. Write a junction that takes ITrainBus through its constructor and calls RunAsync with the child's input, passing its CancellationToken.
  2. Return the merged result from the junction.
  3. Chain the junction where the child's result is needed.
using Trax.Core.Functional;
using Trax.Core.Junction;
using Trax.Effect.Services.ServiceTrain;
using Trax.Mediator.Services.TrainBus;
 
public class ParentTrain : ServiceTrain<ParentInput, ParentResult>, IParentTrain
{
    protected override Task<Either<Exception, ParentResult>> Junctions() =>
        Chain<RunChildTrain>().Chain<ValidateParentResult>().Resolve();
}
 
public class RunChildTrain(ITrainBus trainBus) : Junction<ParentInput, ParentResult>
{
    public override async Task<ParentResult> Run(ParentInput input)
    {
        var child = await trainBus.RunAsync<ChildResult>(
            new ChildRequest(input.ChildData),
            CancellationToken
        );
 
        return new ParentResult(input.ParentData, child);
    }
}

The child runs as a train of its own and is not linked to the parent run. RunAsync takes an optional Metadata, but that is a pre-created Pending row for the child to run as, the way the scheduler uses it, not a parent: passing the running parent's metadata is refused with a TrainException.

SDK Reference

Junctions | Chain | AddServices | ITrainBus