Configuring storage providers
Configure built-in storage providers and manage their database schemas.
In-memory
builder.Services.AddMyAppJobs()
.ConfigureStorage(storage => storage.UseInMemory()); Select in-memory storage explicitly. It keeps data in one process and loses it on restart, but it supports every job feature. Use it for development and tests.
Entity Framework Core
dotnet add package Immediate.Jobs.EntityFrameworkCore --prerelease Prefer a dedicated, application-owned JobsDbContext so the jobs schema stays separate from your
application’s business model. The context can still use the same physical database if that suits
your deployment:
// The application's business data uses its own context and model.
builder.Services.AddDbContext<AppDbContext>(db =>
db.UseNpgsql(appConnectionString));
// Immediate.Jobs uses a separate context and model.
builder.Services.AddDbContextFactory<JobsDbContext>(db =>
db.UseNpgsql(jobsConnectionString)); // PostgreSQL
// db.UseSqlite(jobsConnectionString); // SQLite
// db.UseSqlServer(jobsConnectionString); // SQL Server
builder.Services.AddMyAppJobs()
.ConfigureStorage(storage => storage
.UseEntityFrameworkCore<JobsDbContext>()
.UseSingleServer());
public sealed class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
public DbSet<Order> Orders => Set<Order>();
}
public sealed class Order
{
public Guid Id { get; set; }
}
public sealed class JobsDbContext(DbContextOptions<JobsDbContext> options) : DbContext(options)
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.AddImmediateJobs(schema: "background"); // omit the schema for SQLite
}
} AddImmediateJobs configures the EF Core model but does not ship or apply migration files. Generate
an application-owned migration explicitly after adding the model:
dotnet ef migrations add CreateImmediateJobsSchema
--context JobsDbContext
--output-dir Migrations/ImmediateJobs Run the command from the startup project. If the context and startup application are in different
projects, also pass the appropriate --project and --startup-project paths. Apply the generated
migration through the application’s normal deployment process, or locally with:
dotnet ef database update --context JobsDbContext The generated migration creates the seven Immediate.Jobs tables, indexes and constraints. EnsureCreated is appropriate only for samples or disposable databases. Using an existing business DbContext is supported, but it couples the jobs schema to that model.
LinqToDB
dotnet add package Immediate.Jobs.LinqToDB --prerelease using LinqToDB;
using LinqToDB.Data;
using LinqToDB.Extensions.DependencyInjection;
var dataOptions = new DataOptions().UsePostgreSQL(connectionString);
// new DataOptions().UseSQLite(connectionString);
// new DataOptions().UseSqlServer(connectionString);
builder.Services.AddLinqToDBContext<JobsDataConnection>(() => dataOptions);
await using (var connection = new JobsDataConnection(dataOptions))
{
await connection.CreateImmediateJobsSchemaAsync(
schema: "background", // must be null for SQLite
CancellationToken.None
);
}
builder.Services.AddMyAppJobs()
.ConfigureStorage(storage => storage
.UseLinqToDB<JobsDataConnection>(schema: "background")
.UseSingleServer());
public sealed class JobsDataConnection(DataOptions options) : DataConnection(options); Register the DataConnection type with dependency injection. Jobs resolves it when storage work
starts. The application owns DataOptions, the matching ADO.NET driver and the database schema.
The helper supports SQLite (without a named schema), PostgreSQL and SQL Server. It creates the
tables and indexes for a new database.
Redis
dotnet add package Immediate.Jobs.Redis --prerelease Register an IConnectionMultiplexer, then select Redis storage:
using StackExchange.Redis;
builder.Services.AddSingleton<IConnectionMultiplexer>(_ =>
ConnectionMultiplexer.Connect("localhost:6379"));
builder.Services.AddMyAppJobs()
.ConfigureStorage(storage => storage
.UseRedis()
.ConfigureRedis(redis =>
{
redis.Database = 1;
redis.KeyPrefix = "billing-jobs";
})); The provider uses the registered connection and does not dispose it. The dependency injection
container disposes the connection in this example because it creates the singleton. If you
register an existing instance, its owner must dispose it. Database defaults to -1 (server
default), and KeyPrefix defaults to immediate-jobs. The prefix cannot contain { or } because
Jobs uses those characters internally. Jobs validates these options at startup.
ConfigureRedis also accepts an OptionsBuilder<RedisJobStorageOptions> action. Use it to bind an IConfiguration section:
builder.Services.AddMyAppJobs()
.ConfigureStorage(storage => storage
.UseRedis()
.ConfigureRedis(options => options.Bind(
builder.Configuration.GetSection("ImmediateJobs:Redis")))); You can use BindConfiguration("ImmediateJobs:Redis") when the section comes from the
configuration registered with dependency injection.
Redis always selects distributed mode and supports queue plus recurring capabilities. It does not support graph workflows or fair queues.
Call ConfigureStorage exactly once. With EF Core or LinqToDB, choose UseSingleServer() for one
scheduler process or UseDistributed() for more than one. Jobs defaults to single-server mode
when neither is selected. Redis always uses distributed mode.
Starting Jobs does not create or update a database schema. Keep every Immediate.Jobs provider
package at the same preview version as the core package. Create test databases from the current EF
model or with CreateImmediateJobsSchemaAsync.