Junction

The base class of a junction: one unit of work in a train's chain, taking a TIn and producing a TOut. You implement Run; the base class handles the railway. When an earlier junction has failed, Run is not called and the failure passes through.

In a ServiceTrain, derive from EffectJunction instead when the junction should be visible to the junction logger and junction progress.

Signature

namespace Trax.Core.Junction;
 
public interface IJunction<TIn, TOut>
{
    Task<TOut> Run(TIn input);
}
 
public abstract class Junction<TIn, TOut> : IJunction<TIn, TOut>
{
    protected Junction();
 
    public CancellationToken CancellationToken { get; protected set; }
 
    public abstract Task<TOut> Run(TIn input);
}

IJunction<TIn, TOut> and Junction<TIn, TOut> also carry a public RailwayJunction method, and Junction a public Result property. Both are hidden from completion: the train calls them, you do not.

Type Parameters

Type ParameterDescription
TInThe junction's input. The train takes it from Memory by type. A tuple input is assembled from several Memory values.
TOutThe junction's output. The train stores it in Memory by type for later junctions and for Resolve(). Use Unit for a junction that produces nothing.

Members

MemberDescription
Run(TIn input)Your implementation. Return the output, or throw to fail the train.
CancellationTokenThe running train's token, set before Run is called. Pass it to anything you await.

Behavior

  • A failed predecessor skips Run. The earlier failure is returned unchanged.
  • Cancellation is checked first. If the train's token is already cancelled, Run is not called and the run ends cancelled.
  • An exception becomes the failure. Whatever Run throws is caught and returned as the train's Left, with a TrainExceptionData (train name, run ExternalId, junction name, exception type, message, stack trace) attached in exception.Data["TrainExceptionData"]. The exception's own message is not changed. An OperationCanceledException thrown while the train's token is cancelled propagates as cancellation instead, with no data attached. See TrainException.

Example

using Trax.Core.Junction;
 
public class ChargePayment(IPaymentGateway gateway) : Junction<ValidatedOrder, PaymentReceipt>
{
    public override async Task<PaymentReceipt> Run(ValidatedOrder order) =>
        await gateway.Charge(order.CustomerId, order.Total, CancellationToken);
}

The train builds the junction itself, taking IPaymentGateway for its constructor from Memory or, in a ServiceTrain, from the container. Use constructor injection; do not put [Inject] on a junction's properties (see Inject).

Remarks

  • A junction instance is created for each chain step. Keep per-run state in locals, not fields.
  • Junction does not record anything. EffectJunction adds the per-junction metadata the junction effects read.

See Junctions for the concepts.

Package

dotnet add package Trax.Core