Skip to content

TraxSharp/Trax.Effect

Repository files navigation

Trax.Effect

Build NuGet Version NuGet Downloads .NET License: MIT Last Commit codecov Docs

Effect system for Trax.Core. Upgrades a bare locomotive into a full commercial train service with journey logging, station services, and dependency injection.

The Trax Stack

Trax is a layered framework split across several repos. You can stop at whatever layer solves your problem. You are here: Trax.Effect.

Repo Adds
Trax.Core Pipelines, junctions, railway error propagation
Trax.Effect Execution logging, DI, pluggable storage
Trax.Mediator Decoupled dispatch via TrainBus
Trax.Scheduler Cron schedules, retries, dead-letter queues
Trax.Api GraphQL API for remote access
Trax.Dashboard Blazor monitoring UI
Trax.Cli trax-cli project scaffolding tool
Trax.Samples Sample apps and a dotnet new template

Full documentation: traxsharp.net/docs.

What This Does

Trax.Core gives you Train<TIn, TOut>: a locomotive that carries cargo through a sequence of stops. That's enough for pure logic, but production services need to know what ran, when it departed, whether it arrived, what it was carrying, and what went wrong if it derailed.

Trax.Effect adds the ServiceTrain<TIn, TOut> base class, a full commercial train service that wraps every journey with:

  • Journey logging: a persistent metadata record for each run (state, timing, cargo in, cargo out, derailment details)
  • Station services: pluggable effect providers that fire during execution (data persistence, logging, parameter serialization, progress tracking)
  • DI integration: stops are resolved from IServiceProvider, so you get constructor injection out of the box

Installation

dotnet add package Trax.Effect

For data persistence, pick a storage depot:

# PostgreSQL (production)
dotnet add package Trax.Effect.Data.Postgres

# In-memory (testing / prototyping)
dotnet add package Trax.Effect.Data.InMemory

Optional station services:

dotnet add package Trax.Effect.Provider.Json        # Debug logging of train state
dotnet add package Trax.Effect.Provider.Parameter    # Serialize cargo to the journey log

Setup

Register station services in your IServiceCollection:

builder.Services.AddTrax(trax =>
    trax.AddEffects(effects =>
        effects.UsePostgres(connectionString).SaveTrainParameters().AddJunctionLogger(serializeJunctionData: true).AddJunctionProgress()
    )
);

For development or tests, swap Postgres for in-memory:

builder.Services.AddTrax(trax =>
    trax.AddEffects(effects =>
        effects.UseInMemory().AddJson()
    )
);

Usage

Inherit from ServiceTrain instead of Train:

public interface ICreateUserTrain : IServiceTrain<CreateUserRequest, User> { }

public class CreateUserTrain : ServiceTrain<CreateUserRequest, User>, ICreateUserTrain
{
    protected override async Task<Either<Exception, User>> RunInternal(CreateUserRequest input)
        => Activate(input)
            .Chain<ValidateEmailJunction>()
            .Chain<CreateUserInDatabaseJunction>()
            .Chain<SendWelcomeEmailJunction>()
            .Resolve();
}

The route syntax is identical to Train. The difference is what happens around it. ServiceTrain automatically opens a journey log when the train departs, updates it when it arrives, persists effect data at each station, and records the derailment details if any stop fails.

Junctions work the same way, with full DI:

public class CreateUserInDatabaseJunction(AppDbContext db) : Junction<CreateUserRequest, User>
{
    public override async Task<User> Run(CreateUserRequest input)
    {
        var user = new User { Email = input.Email, Name = input.Name };
        db.Users.Add(user);
        await db.SaveChangesAsync();
        return user;
    }
}

Journey Lifecycle

Every ServiceTrain journey transitions through:

Pending → InProgress → Completed
                     → Failed
                     → Cancelled

Think of it as: the train is boarding (Pending), in transit (InProgress), and then either arrives (Completed), derails (Failed), or is pulled from service (Cancelled). These states are persisted in the journey log and queryable through the data layer.

Station Services

Service Package What it does
Postgres Trax.Effect.Data.Postgres Persists journey logs and execution data to PostgreSQL
InMemory Trax.Effect.Data.InMemory In-memory store for tests and local dev
Json Trax.Effect.Provider.Json Logs state transitions as JSON for debugging
Parameter Trax.Effect.Provider.Parameter Serializes train cargo (inputs/outputs) into the journey log
JunctionLogger Built-in Logs each junction's execution with optional cargo serialization
JunctionProgress Built-in Tracks per-junction progress and checks for cancellation signals

Station services compose, so enable as many as you need:

effects
    .UsePostgres(connectionString)
    .AddJson()
    .SaveTrainParameters()
    .AddJunctionLogger(serializeJunctionData: true)
    .AddJunctionProgress();

DI Registration Helpers

Register your trains as scoped services with proper interface mapping:

builder.Services.AddScopedTraxRoute<ICreateUserTrain, CreateUserTrain>();
builder.Services.AddTransientTraxRoute<IProcessOrderTrain, ProcessOrderTrain>();

Or use AddMediator (from Trax.Mediator) to auto-register all trains in an assembly.

Next Layer

When you need decoupled dispatch (callers don't know which train handles a request), move up to Trax.Mediator.

License

MIT

Trademark & Brand Notice

Trax is an open-source .NET framework provided by TraxSharp. This project is an independent community effort and is not affiliated with, sponsored by, or endorsed by the Utah Transit Authority, Trax Retail, or any other entity using the "Trax" name in other industries.

About

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages