AddTraxWorker

Registers a standalone worker process that polls the background_job table and executes trains. No scheduler logic — just execution.

Signature

public static IServiceCollection AddTraxWorker(
    this IServiceCollection services,
    Action<LocalWorkerOptions>? configure = null
)

Parameters

ParameterTypeRequiredDescription
configureAction<LocalWorkerOptions>?NoOptional callback to customize worker count, polling interval, and timeouts

LocalWorkerOptions

PropertyTypeDefaultDescription
WorkerCountintEnvironment.ProcessorCountNumber of concurrent worker tasks polling for jobs
PollingIntervalTimeSpan1 secondHow often idle workers poll for new jobs
VisibilityTimeoutTimeSpan30 minutesHow long a claimed job stays invisible before another worker can reclaim it (crash recovery)
ShutdownTimeoutTimeSpan30 secondsGrace period for in-flight jobs during shutdown

These are the same options used by ConfigureLocalWorkers.

Examples

Basic Standalone Worker

var builder = WebApplication.CreateBuilder(args);
 
builder.Services.AddTrax(trax => trax
    .AddEffects(effects => effects
        .UsePostgres(connectionString)
    )
    .AddMediator(typeof(MyTrain).Assembly)
);
builder.Services.AddTraxWorker();
 
var app = builder.Build();
app.Run();

Custom Worker Configuration

builder.Services.AddTraxWorker(opts =>
{
    opts.WorkerCount = 4;
    opts.PollingInterval = TimeSpan.FromSeconds(2);
    opts.VisibilityTimeout = TimeSpan.FromMinutes(15);
    opts.ShutdownTimeout = TimeSpan.FromMinutes(1);
});

Multiple Worker Processes

You can run multiple standalone worker processes against the same database. PostgreSQL's FOR UPDATE SKIP LOCKED ensures each job is claimed by exactly one worker — no duplicates, no coordination needed.

┌── Worker Process A ──┐    ┌── Worker Process B ──┐
│  4 worker tasks       │    │  4 worker tasks       │
│  polling same table   │    │  polling same table   │
└───────────┬───────────┘    └───────────┬───────────┘
            │                            │
            └──────────┬─────────────────┘
                       ▼
              background_job table
              (SKIP LOCKED ensures
               no duplicate claims)

What It Registers

AddTraxWorker() internally calls AddTraxJobRunner() and adds the worker service:

ServiceLifetimeDescription
All services from AddTraxJobRunner()(various)Execution pipeline (JobRunnerTrain, CancellationRegistry, etc.)
LocalWorkerOptionsSingletonWorker configuration
LocalWorkerServiceHosted ServiceBackground worker that polls background_job and executes trains

Not registered: ManifestManager, JobDispatcher, polling services, startup service. This process only executes — it doesn't schedule or dispatch.

How It Differs from the Scheduler's Local Workers

AspectScheduler (with Postgres)AddTraxWorker()
Used inFull scheduler processStandalone worker process
SchedulingYes (ManifestManager, JobDispatcher)No
DispatchingYes (writes to WorkQueue, background_job)No
ExecutionYes (LocalWorkerService)Yes (LocalWorkerService)
Job submitterRegisters PostgresJobSubmitterDoes not register any submitter

Shared Requirements

The standalone worker must:

  • Reference the same train assemblies passed to AddMediator() — train types are resolved by fully-qualified name
  • Connect to the same Postgres database — metadata, manifests, and state are shared across all processes
  • Register the effect systemAddTrax() with UsePostgres() is required

Package

dotnet add package Trax.Scheduler

See Also