Run / RunEither
Executes the train from the outside. Run throws on failure; RunEither returns an Either<Exception, TReturn> for Railway-oriented error handling.
These are called by consumers of the train, not inside RunInternal.
Signatures
Run (throws on failure)
public virtual async Task<TReturn> Run(TInput input, CancellationToken cancellationToken = default)RunEither (returns Either)
public Task<Either<Exception, TReturn>> RunEither(TInput input)Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
input | TInput | Yes | The input data for the train |
cancellationToken | CancellationToken | No | Token to monitor for cancellation requests. When provided, it is stored on the Train.CancellationToken property and propagated to every junction before execution. Defaults to CancellationToken.None when omitted. |
> Note: RunEither does not accept a CancellationToken parameter. Set the token via Run or by assigning Train.CancellationToken directly before calling RunEither.
Returns
Run:Task<TReturn>— the train result. Throws the captured exception if the train failed. ThrowsOperationCanceledExceptionif the token is cancelled.RunEither:Task<Either<Exception, TReturn>>—Lefton failure,Righton success. Note: cancellation still throwsOperationCanceledExceptionrather than returningLeft— cancellation is not a business error.
Examples
Using Run (imperative style)
try
{
var result = await train.Run(new OrderInput { OrderId = "123" });
Console.WriteLine($"Order processed: {result.ConfirmationId}");
}
catch (Exception ex)
{
Console.WriteLine($"Train failed: {ex.Message}");
}Using RunEither (functional style)
var result = await train.RunEither(new OrderInput { OrderId = "123" });
result.Match(
Right: success => Console.WriteLine($"Order processed: {success.ConfirmationId}"),
Left: error => Console.WriteLine($"Train failed: {error.Message}")
);With CancellationToken
// From an ASP.NET controller
public async Task<IActionResult> ProcessOrder(
OrderInput input,
CancellationToken cancellationToken)
{
var result = await train.Run(input, cancellationToken);
return Ok(result);
}Behavior
- If a
CancellationTokenis provided, stores it on theTrain.CancellationTokenproperty. - Initializes
MemorywithUnit.Default. - Calls
RunInternal(input)— the user-implemented method. Run: Unwraps theEitherresult. IfLeft, rethrows the exception. IfRight, returns the value.RunEither: Returns theEitherdirectly without unwrapping.
During junction execution, the train's CancellationToken is automatically propagated to each junction before its Run method is called. Junctions access the token via this.CancellationToken. Before each junction executes, CancellationToken.ThrowIfCancellationRequested() is called — if the token is already cancelled, the junction is skipped entirely.
Remarks
RunEitheris useful when you want functional-style error handling without try/catch. It pairs naturally with LanguageExt'sMatch,Map,Bind, etc.- In most applications, trains are executed through
ITrainBus.RunAsync(which callsRuninternally) rather than callingRundirectly. See TrainBus. - The
cancellationTokenparameter stores the token before callingRunInternal. All junctions in the chain then receive the token automatically. See Cancellation Tokens for details on how cancellation propagates through the pipeline.