PostgreSQL readiness signals for Veggerby.Ignition - verify database connections and schema during application startup.
$ dotnet add package Veggerby.Ignition.PostgresPostgreSQL readiness signals for Veggerby.Ignition - verify database connections and schema during application startup.
dotnet add package Veggerby.Ignition.Postgres
dotnet add package Npgsql
The recommended approach uses NpgsqlDataSource for better connection pooling and DI integration:
// Register NpgsqlDataSource in DI container
builder.Services.AddNpgsqlDataSource(
"Host=localhost;Database=mydb;Username=user;Password=pass");
// Add PostgreSQL readiness signal (automatically resolves NpgsqlDataSource from DI)
builder.Services.AddIgnition();
builder.Services.AddPostgresReadiness();
var app = builder.Build();
await app.Services.GetRequiredService<IIgnitionCoordinator>().WaitAllAsync();
Why NpgsqlDataSource?
For simpler scenarios or when NpgsqlDataSource isn't registered in DI:
builder.Services.AddIgnition();
builder.Services.AddPostgresReadiness(
"Host=localhost;Database=mydb;Username=user;Password=pass");
var app = builder.Build();
await app.Services.GetRequiredService<IIgnitionCoordinator>().WaitAllAsync();
builder.Services.AddNpgsqlDataSource(connectionString);
builder.Services.AddPostgresReadiness(options =>
{
options.ValidationQuery = "SELECT 1";
options.Timeout = TimeSpan.FromSeconds(5);
});
builder.Services.AddNpgsqlDataSource(connectionString);
builder.Services.AddPostgresReadiness(options =>
{
// Verify specific table exists
options.ValidationQuery = "SELECT 1 FROM users LIMIT 1";
options.Timeout = TimeSpan.FromSeconds(10);
});
| Property | Type | Description | Default |
|---|---|---|---|
Timeout | TimeSpan? | Per-signal timeout override | null (uses global timeout) |
ValidationQuery | string? | SQL query to execute after connection | null (connection only) |
The signal emits structured logs at different levels:
When tracing is enabled, the signal adds these tags:
postgres.server: Host from connection stringpostgres.database: Database name from connection stringpostgres.validation_query: Validation query if configuredbuilder.Services.AddIgnition();
builder.Services.AddPostgresReadiness(connectionString);
builder.Services
.AddHealthChecks()
.AddCheck<IgnitionHealthCheck>("ignition-readiness");
With NpgsqlDataSource (when you have multiple databases):
// Primary database
builder.Services.AddNpgsqlDataSource(
primaryConnectionString,
serviceKey: "primary");
// Read replica
builder.Services.AddNpgsqlDataSource(
replicaConnectionString,
serviceKey: "replica");
// Note: Currently AddPostgresReadiness only supports the default (non-keyed) data source.
// For multiple databases, register custom signals manually:
builder.Services.AddIgnitionSignal(sp =>
{
var primaryDs = sp.GetRequiredKeyedService<NpgsqlDataSource>("primary");
var logger = sp.GetRequiredService<ILogger<PostgresReadinessSignal>>();
return new PostgresReadinessSignal(primaryDs, new PostgresReadinessOptions
{
ValidationQuery = "SELECT 1",
Timeout = TimeSpan.FromSeconds(5)
}, logger);
});
builder.Services.AddIgnitionSignal(sp =>
{
var replicaDs = sp.GetRequiredKeyedService<NpgsqlDataSource>("replica");
var logger = sp.GetRequiredService<ILogger<PostgresReadinessSignal>>();
return new PostgresReadinessSignal(replicaDs, new PostgresReadinessOptions
{
ValidationQuery = "SELECT 1",
Timeout = TimeSpan.FromSeconds(10)
}, logger);
});
With connection strings (simpler for multiple databases):
// Primary database
builder.Services.AddPostgresReadiness(
primaryConnectionString,
options =>
{
options.ValidationQuery = "SELECT 1";
options.Timeout = TimeSpan.FromSeconds(5);
});
// Read replica
builder.Services.AddPostgresReadiness(
replicaConnectionString,
options =>
{
options.ValidationQuery = "SELECT 1";
options.Timeout = TimeSpan.FromSeconds(10);
});
Note: Multiple PostgreSQL signals will share the same name ("postgres-readiness"). For distinct signal names, implement custom IIgnitionSignal instances.
Connection failures and query execution errors are logged and propagated:
try
{
await coordinator.WaitAllAsync();
}
catch (AggregateException ex)
{
foreach (var inner in ex.InnerExceptions)
{
if (inner is NpgsqlException pgEx)
{
// Handle PostgreSQL-specific errors
Console.WriteLine($"PostgreSQL Error: {pgEx.Message}");
}
}
}
MIT License. See LICENSE.