-
Notifications
You must be signed in to change notification settings - Fork 4
Database seeding
Seeding initializes a database context once — to create default data, an admin account, initial configuration. Scrinium tracks whether a context has been seeded and skips it on subsequent starts, and serializes seeding across application instances — so a context is seeded once however many instances start together.
Put your initialization in a SeedAsync override on the context. Use its
repositories as usual:
public class SampleDbContext : DbContext, ISampleDbContext
{
public IRepository<Cat, string> Cats { get; } = new Repository<Cat, string>("cats");
protected override async Task SeedAsync()
{
await Cats.CreateAsync(new Cat("Adam", new DateTime(2020, 1, 1)));
await SaveChangesAsync();
}
// ...
}The default SeedAsync does nothing, so override it only when you have data to seed.
Call SeedDbContexts() on the built app. It resolves every registered context in a dedicated scope,
gives each one its own execution context, and runs their seeds in parallel,
each only if not already seeded:
var app = builder.Build();
// ... middleware ...
app.SeedDbContexts();
app.Run();You can also trigger a single context directly with SeedIfNeededAsync().
-
SeedIfNeededAsync()checksIsSeeded, claims the db context lock, then re-checks and runsSeedAsyncunder exclusive access, first executing a full db-context migration (a new operation — on a fresh database this is what builds the indexes). On success it marks the context seeded (cached on the engine asIsSeededCache) and logs aSeedOperationin the_db_opscollection. - Three things keep it once-only, at three different scopes: exclusive access serializes the flows
of this process, the db context lock serializes the application instances against the same
database, and the persisted
SeedOperation— whatIsSeededreads — prevents reseeding across restarts. - On a read-only context,
SeedIfNeededAsynclogs and returnsfalsewithout touching the database: its lifecycle belongs to the owner application.
Because it runs under exclusive access, every other flow of this context — in this process — is locked out of its collections while seeding proceeds — keep seed logic focused.
While another owner holds the db context lock — another instance seeding the same database, or a
migration, or a diagnostic dry run — SeedIfNeededAsync waits, retrying every 5
seconds (more often when its wait timeout is under 20 seconds) and re-reading the seeding state from
the database between attempts. It returns false without seeding as soon as a re-read finds the
context seeded; a lock freed by a migration or a dry run instead lets the wait claim it and seed.
The wait is bounded, since the caller blocks on it: when the timeout elapses with the lock still
held, seeding fails with a ScriniumDbSeedingException. Its default is the lease duration of that
call (ResourceLock.DefaultLeaseDuration, 10 minutes, unless you pass another). So with every
instance on the same lease duration, a dead owner's lease always expires inside the wait, and only an
owner still alive, working longer than the wait, fails your seeding.
The wait and the lease are both arguments — on a single context:
await db.SeedIfNeededAsync(
lockWaitTimeout: TimeSpan.FromMinutes(30), // a long migration may be running elsewhere
lockLeaseDuration: TimeSpan.FromMinutes(20)); // how long a crash here blocks the othersand on the startup call, which forwards them to every context it seeds:
app.SeedDbContexts(lockWaitTimeout: TimeSpan.FromMinutes(30));Note. Raise
lockWaitTimeoutwhen your seeds are long, or when a startup can coincide with a migration: it must cover the whole work of the other owner, not just its lease.
Tip. Seeding runs in its own scope. If your application raises its own domain events on create/save and you don't want them firing during seed, disable that dispatch inside
SeedAsync— Scrinium itself has no event facility to turn off. Seed logic runs once, so it needn't be idempotent.
Next: Migrations for evolving existing data, or Startup and configuration for where
SeedDbContexts fits in the pipeline.
Scrinium — source · issues (SCR) · GNU LGPL-3.0 · info@etherna.io
Getting started
Core concepts
Working with data
Serialization & mapping
Operations & maintenance
Advanced & reference