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
| Parameter | Type | Required | Description |
|---|---|---|---|
configure | Action<LocalWorkerOptions>? | No | Optional callback to customize worker count, polling interval, and timeouts |
LocalWorkerOptions
| Property | Type | Default | Description |
|---|---|---|---|
WorkerCount | int | Environment.ProcessorCount | Number of concurrent worker tasks polling for jobs |
PollingInterval | TimeSpan | 1 second | How often idle workers poll for new jobs |
VisibilityTimeout | TimeSpan | 30 minutes | How long a claimed job stays invisible before another worker can reclaim it (crash recovery) |
ShutdownTimeout | TimeSpan | 30 seconds | Grace 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:
| Service | Lifetime | Description |
|---|---|---|
All services from AddTraxJobRunner() | (various) | Execution pipeline (JobRunnerTrain, CancellationRegistry, etc.) |
LocalWorkerOptions | Singleton | Worker configuration |
LocalWorkerService | Hosted Service | Background 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
| Aspect | Scheduler (with Postgres) | AddTraxWorker() |
|---|---|---|
| Used in | Full scheduler process | Standalone worker process |
| Scheduling | Yes (ManifestManager, JobDispatcher) | No |
| Dispatching | Yes (writes to WorkQueue, background_job) | No |
| Execution | Yes (LocalWorkerService) | Yes (LocalWorkerService) |
| Job submitter | Registers PostgresJobSubmitter | Does 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 system —
AddTrax()withUsePostgres()is required
Package
dotnet add package Trax.Scheduler
See Also
- Remote Execution — architecture overview and deployment models
- ConfigureLocalWorkers — customizing local workers within the scheduler process
- AddTraxJobRunner — push-based alternative (HTTP endpoint)