Reference

Dispatch limits

Source MediatorConfiguration.cs, TraxMediatorBuilder.Settings.cs, ConcurrencyLimiter.cs, TrainInputReader.cs, TrainExecutionService.cs, TrainInputValidationException.cs, QueueHookTimeoutException.cs

Three limits on TraxMediatorBuilder bound what one caller can make a host do through ITrainExecutionService, the service every caller-built run and enqueue goes through (GraphQL train fields, the operations namespace and the dashboard). Work the scheduler or a remote worker runs through ITrainBus is not subject to them.

LimitBuilder methodDefaultApplies to
Concurrent runs per principalPerPrincipalMaxConcurrentRun(int)noneITrainExecutionService.RunAsync
Input JSON sizeWithMaxInputJsonBytes(int)262,144 bytes (256 KiB)RunAsync, QueueAsync and PrepareAsync on ITrainExecutionService, and so IOperationsService.QueueTrainAsync and RunTrainAsync
OnQueue hook durationWithMaxQueueHookDuration(TimeSpan)30 secondsAn enqueue's OnQueue hook, and the hook a run started through IOperationsService.RunTrainAsync runs

The values are read back from MediatorConfiguration.

using Trax.Effect.Data.Postgres.Extensions;
using Trax.Effect.Extensions;
using Trax.Mediator.Extensions;
 
services.AddTrax(trax => trax
    .AddEffects(effects => effects.UsePostgres(connectionString))
    .AddMediator(mediator => mediator
        .ScanAssemblies(typeof(Program).Assembly)
        .PerPrincipalMaxConcurrentRun(10)
        .WithMaxInputJsonBytes(64 * 1024)
        .WithMaxQueueHookDuration(TimeSpan.FromSeconds(10))));

Concurrent runs per principal

ArgumentA positive number of runs. Zero or less throws ArgumentOutOfRangeException ("PerPrincipalMaxConcurrentRun must be positive.") at the builder call.
CountedRuns through ITrainExecutionService.RunAsync that are executing or waiting. Queued work is not counted.
PrincipalThe id ICurrentPrincipalProvider.GetCurrentPrincipalId() returns, compared ordinally. AddMediator registers a provider that returns null, so the limit has no effect until another is registered. AddTraxApi (which AddTraxGraphQL calls) registers one that returns the authenticated request user's trax:principal-id claim.
No principalA run with a null or empty id (an anonymous request, a run with no request) is not limited per principal.
Over the limitThe run waits on its principal's semaphore until one of that principal's runs finishes. It is not refused.
OrderA run takes its per-train slot, then its per-principal slot, then the global slot, and releases them in reverse.
Other limitsThe per-train and global limits apply as well; see Concurrency limiting.

The principal id is scheme-qualified (TraxApiKey:alice, TraxJwt:alice), so one person signed in through two schemes has two budgets. A custom provider must return an id the caller cannot choose: see ICurrentPrincipalProvider.

Input JSON size

ArgumentA positive number of bytes. Zero or less throws ArgumentOutOfRangeException ("MaxInputJsonBytes must be positive.").
MeasuredThe UTF-8 byte length of the caller's input JSON, before it is parsed.
WhenAfter authorization and before deserialization: a caller who may not run the train is refused for that first, and an oversized input never reaches the deserializer.
Stored formAn enqueue writes the parsed input back out (indented, every member present) onto its work queue entry. That form is capped at 4 times the limit (TrainInputReader.StoredInputGrowthFactor), checked before the entry is written; writing it stops as soon as it crosses the cap.
RefusalTrainInputValidationException, message "The train input failed validation.". TrainName, ObservedBytes and MaxBytes carry the detail for logs.
Over GraphQLCode TRAX_INVALID_INPUT, with the same message. Through IOperationsService (the operations namespace, the dashboard), a failed result with a message.

Input is read without JSON reference handling: $id, $ref and $values are not honoured, so the parsed input is the tree the caller sent. A property given twice, in any casing, is refused. The reading rules are listed under TrainInputReader.

A remote runner's HTTP entry points read at most TraxJobRunnerOptions.MaxRequestBodyBytes (8 MiB by default), which holds an input at the default stored-form cap. Raise both together.

OnQueue hook duration

ArgumentA positive duration of at most int.MaxValue milliseconds, or Timeout.InfiniteTimeSpan for no limit. Anything else throws ArgumentOutOfRangeException.
MeasuredHow long the hook runs while its enqueue holds a pooled connection and an open transaction.
At the limitThe hook's cancellation token is cancelled and the enqueue stops waiting for it. The enqueue rolls back everything the hook wrote on the enqueue's context and releases the connection.
RefusalQueueHookTimeoutException, message <train>.OnQueue ran longer than <n>s, the limit set by MaxQueueHookDuration, so the enqueue was rolled back. .... TrainName and Limit carry the detail. A warning is logged.
Through IOperationsServiceA failed result whose message includes the exception's.
A hook that keeps runningIt is not stopped. It runs on without the enqueue's context or transaction, a side effect it writes elsewhere may still land, and an enqueue it starts from then on is refused. A hook that blocks its thread rather than awaiting is not interrupted until it yields.
Deferring trainsA train that defers queue promotion (DeferQueuePromotion) runs its hook holding no connection, and this limit does not apply to it.

The hook itself is described under OnQueue.

See also

SDK Reference

MediatorConfiguration | Concurrency limiting | ICurrentPrincipalProvider | ITrainExecutionService