UseRemoteRun

Configures the scheduler to offload synchronous run execution to a remote HTTP endpoint instead of executing in-process. The call blocks until the remote train completes and returns the output.

Signature

public SchedulerConfigurationBuilder UseRemoteRun(
    Action<RemoteRunOptions> configure
)

Parameters

ParameterTypeRequiredDescription
configureAction<RemoteRunOptions>YesCallback to set the remote endpoint URL and HTTP client options

Returns

SchedulerConfigurationBuilder, for continued fluent chaining.

RemoteRunOptions

PropertyTypeDefaultDescription
BaseUrlstring(required)The URL of the remote endpoint that receives run requests (e.g., https://my-runner.example.com/trax/run)
ConfigureHttpClientAction<HttpClient>?nullOptional callback to configure the HttpClient (add auth headers, custom timeouts, or any other HTTP configuration)
TimeoutTimeSpan5 minutesHTTP request timeout. Longer default than UseRemoteWorkers (30s) because run requests block until the train completes
RetryHttpRetryOptions(see below)Retry options for transient HTTP failures (429, 502, 503). Same configuration as RemoteWorkerOptions.Retry
SigningKeybyte[]?nullThe key shared with the runner's AddTraxJobRunner(runner => runner.SigningKey = ...), at least 32 bytes. When set, each request (and each retry) carries a Trax-Signature the runner verifies. See Authorization Posture

Examples

Basic Usage

services.AddTrax(trax => trax
    .AddEffects(effects => effects
        .UsePostgres(connectionString)
    )
    .AddMediator(assemblies)
    .AddScheduler(scheduler => scheduler
        .UseRemoteWorkers(
            remote => remote.BaseUrl = "https://my-runner.example.com/trax/execute",
            routing => routing.ForTrain<IMyTrain>()
        )
        .UseRemoteRun(remote =>
            remote.BaseUrl = "https://my-runner.example.com/trax/run"
        )
    )
);

With a Signing Key

.UseRemoteRun(remote =>
{
    remote.BaseUrl = "https://my-runner.example.com/trax/run";
    remote.SigningKey = Convert.FromBase64String(configuration["Trax:RunnerSigningKey"]!);
})

A run request must reach the runner within its MaxClockSkew (five minutes by default) and is accepted once. For a runner that uses an authorization policy instead, add its credentials with ConfigureHttpClient.

With Custom Timeout

.UseRemoteRun(remote =>
{
    remote.BaseUrl = "https://my-runner.example.com/trax/run";
    remote.Timeout = TimeSpan.FromMinutes(10);
})

Remote Side Setup

The remote process registers AddTraxJobRunner with a posture and maps the run endpoint with UseTraxRunEndpoint():

var builder = WebApplication.CreateBuilder(args);
 
builder.Services.AddTrax(trax => trax
    .AddEffects(effects => effects
        .UsePostgres(connectionString)
    )
    .AddMediator(typeof(MyTrain).Assembly)
);
builder.Services.AddTraxJobRunner(runner =>
    runner.SigningKey = Convert.FromBase64String(builder.Configuration["Trax:RunnerSigningKey"]!)
);
 
var app = builder.Build();
app.UseTraxRunEndpoint("/trax/run");
app.Run();

If the remote also handles queued jobs, map both endpoints:

var app = builder.Build();
app.UseTraxJobRunner("/trax/execute");  // queue path
app.UseTraxRunEndpoint("/trax/run");    // synchronous run path
app.Run();

Registered Services

UseRemoteRun() registers:

ServiceLifetimeDescription
RemoteRunOptionsSingletonConfiguration options
IRunExecutorTransientA typed HttpClient client (AddHttpClient). Replaced with an internal implementation that dispatches run requests via HTTP POST and blocks until the response

Note: Without UseRemoteRun(), the default LocalRunExecutor executes trains in-process via ITrainBus.RunByNameAsync(). UseRemoteRun() overrides this via last-registration-wins.

How It Works

When a GraphQL run* mutation is called, the IRunExecutor registered by UseRemoteRun():

  1. Serializes a RemoteRunRequest containing the train name, input JSON, and input type
  2. POSTs the JSON payload to BaseUrl
  3. Blocks until the remote endpoint returns a RemoteRunResponse
  4. On success: deserializes the train output from the response and returns it to GraphQL
  5. On error: throws a RemoteRunException (a TrainException) with the remote error details. Its PublicMessage is the runner's message for a client, and null for a transport failure or any failure other than a train author's TrainException

The remote endpoint (UseTraxRunEndpoint) calls ITrainExecutionService.RunAsync() locally, which creates metadata, runs the train, and returns the output. Since both processes share the same Postgres database, the metadata is visible to the dashboard.

Differences from UseRemoteWorkers

UseRemoteRunUseRemoteWorkers
Execution pathrun* mutationsqueue* mutations
BlockingYes, blocks until train completesNo, returns immediately with WorkQueueId
ReturnsTrain output (deserialized from response)WorkQueueId + ExternalId
Remote endpointUseTraxRunEndpoint() (/trax/run)UseTraxJobRunner() (/trax/execute)
AbstractionIRunExecutorIJobSubmitter
Default timeout5 minutes30 seconds

Package

dotnet add package Trax.Scheduler

See Also