UsePostgres
Package Trax.Effect.Data.PostgresNamespace Trax.Effect.Data.Postgres.ExtensionsSource ServiceExtensions.cs, ModelBuilderExtensions.cs
The PostgreSQL data provider. Persists train metadata, logs, manifests, the work queue, dead letters and the rest
of the trax tables in a Postgres database, and migrates its schema on startup.
Signatures
public static TraxEffectBuilderWithData UsePostgres(
this TraxEffectBuilder configurationBuilder,
string connectionString
)
public static TraxEffectBuilderWithData UsePostgres(
this TraxEffectBuilder configurationBuilder,
string connectionString,
Action<NpgsqlDataSourceBuilder>? configureDataSource
)Parameters
| Parameter | Type | Description |
|---|---|---|
connectionString | string | The Npgsql connection string, such as "Host=localhost;Database=trax;Username=postgres;Password=password" |
configureDataSource | Action<NpgsqlDataSourceBuilder>? | Called on the data source builder after Trax maps its enums and before Build(): pool size, timeouts, multiplexing. null leaves the defaults. |
Returns
TraxEffectBuilderWithData, which carries the methods that need a data provider. See
AddEffects.
Behavior
Unless SkipMigrations was called earlier in the chain,
UsePostgres runs DatabaseMigrator.Migrate(connectionString) synchronously before it registers anything, so the
database must be reachable when the host is configured. See
DatabaseMigrator. It sets HasDataProvider and
HasDatabaseProvider.
- The migration's scripts wait at most five seconds for a table lock. When one gives up, the migrator runs the
pending scripts again, up to ten times, then fails startup with Postgres error
55P03. See Writing Migrations. - Postgres refuses the NUL character in
textandjsonb. Every string Trax writes through this provider has each NUL replaced with U+FFFD. A column that identifies a row (a key, a foreign key, an indexed column, a work queue entry's external id or subject key) is compared exactly, so its NUL is kept and Postgres refuses the write;WorkQueue.Createrefuses a subject key holding a NUL before that. SQLite and the in-memory provider store NUL unchanged. - When Postgres refuses a run's row because of a value it carries (SQLSTATE
22001,22021,22P05or54000, or text the client cannot encode, such as half of a surrogate pair), the data context raisesStoreRefusedContentException, and Trax writes the row again with the output replaced by{"_unrecorded": true}and the failure message and stack trace replaced by fixed text, keeping the state, end time, failure type, junction and class. An input refused on the run's first write is replaced the same way. The original error is logged, and it propagates only when the second write fails too. Lifecycle hooks still receive the real output and failure message. Any other failure propagates without a second write.
The data source
The NpgsqlDataSource is built by the container, once per service provider, with
ModelBuilderExtensions.BuildDataSource(connectionString, configureDataSource), and disposed with that provider,
which closes its connection pool. Two providers built from one service collection each get their own. It maps
these enums to their trax schema types: TrainState, FailureClass, LogLevel, ScheduleType,
DeadLetterStatus, WorkQueueStatus, MisfirePolicy, JunctionRunKind, JunctionRunState and
SnapshotOwnerKind.
BuildDataSource(connectionString) and BuildDataSource(connectionString, configure) are public, for code that
needs a data source mapped the same way outside the container.
Registered services
| Service | Lifetime | Role |
|---|---|---|
NpgsqlDataSource | Singleton | The data source above |
IDbContextFactory<PostgresContext> | Singleton | Creates PostgresContext, Trax's EF Core context over the data source |
| IDataContext | Scoped | A PostgresContext from the factory |
IDataContextProviderFactory | Singleton | The Postgres data context provider factory, registered as a non-toggleable effect, so it persists every run |
| ISqlDialect | Singleton | The Postgres dialect |
| IQueuedWorkListener | Singleton | Hears trax_queued_work notifications from every host |
IInvokedRunListener, ISnapshotNoticeSource | Singleton | The notifications the state machine runtime waits on |
ICheckpointRows | Singleton, if none is registered | The rows checkpoints are stored in |
ITraxFeatureDbConfigurator | Singleton | A DelegateFeatureDbConfigurator that points a feature's own DbContext at the same data source (UseNpgsql), so it needs no AddDbContext of the host's |
Examples
services.AddTrax(trax => trax
.AddEffects(effects => effects
.UsePostgres("Host=localhost;Database=trax;Username=postgres;Password=password")
.AddDataContextLogging()
)
.AddMediator(typeof(IShipOrderTrain).Assembly)
);With the connection pool tuned:
services.AddTrax(trax => trax
.AddEffects(effects => effects
.UsePostgres(connectionString, dataSource =>
{
dataSource.ConnectionStringBuilder.MaxPoolSize = 50;
dataSource.ConnectionStringBuilder.MinPoolSize = 5;
dataSource.ConnectionStringBuilder.ConnectionIdleLifetime = 300;
})
)
.AddMediator(typeof(IShipOrderTrain).Assembly)
);