ICurrentPrincipalProvider

Tells the mediator who the current caller is, as a stable id. Its only use in Trax is bucketing the per-principal concurrency limit on direct runs. It is not used for authorization: nothing here grants or checks access.

Signature

namespace Trax.Mediator.Services.Principal;
 
public interface ICurrentPrincipalProvider
{
    string? GetCurrentPrincipalId();
}

Returns: the current principal's stable id, or null when there is none (the scheduler, a remote worker, an anonymous request). A run with a null or empty id is not limited per principal; the per-train and global limits still apply. Ids are compared ordinally.

Registrations

Registered byImplementation
AddMediatorA default that always returns null, so PerPrincipalMaxConcurrentRun limits nothing on its own
AddTraxApi (called by AddTraxGraphQL)Reads the trax:principal-id claim of the current request's authenticated user. Call it after AddTrax, or the mediator's default wins.

A host outside ASP.NET Core that wants the per-principal limit registers its own as a singleton after AddMediator.

Writing one

  • Singleton, thread-safe. The concurrency limiter is a singleton and resolves the provider once. Read ambient state (the current request, an AsyncLocal) on each call rather than capturing it.
  • Cheap. It is called on every direct run while the per-principal limit is set.
  • An id the caller cannot choose. Use something authenticated, such as the subject claim. An id taken from a header or other client input lets a caller spread its runs across many buckets and escape the limit, because a new id starts with a full budget. Never return a per-request or random value.

Example

using Trax.Mediator.Services.Principal;
 
public sealed class JobContextPrincipalProvider : ICurrentPrincipalProvider
{
    public string? GetCurrentPrincipalId() => JobContext.Current?.TenantId;
}
 
services.AddTrax(trax => trax
    .AddEffects(effects => effects.UsePostgres(connectionString))
    .AddMediator(mediator => mediator
        .ScanAssemblies(typeof(Program).Assembly)
        .PerPrincipalMaxConcurrentRun(5)));
 
services.AddSingleton<ICurrentPrincipalProvider, JobContextPrincipalProvider>();

Package

dotnet add package Trax.Mediator