Skip to content

Choose patch storage

The patch manager is only as durable as the record of what it has applied. Patching needs an IPatchStorage, and starting without one throws when the silo starts. That is intentional: patching against a store that cannot remember what ran would apply every patch on every start.

The record is per store, not per scope or namespace. A patch changes the store itself, so every silo in the cluster must read and write the same record. This differs from jobs storage; see Storage. Pick the storage you deploy, not the one that is convenient locally, and register it next to your jobs storage.

StorageSurvives a restartUse it for
In-memoryNoTests and local development
MongoDBYesHosts that run on MongoDB
SQLYesHosts that run on SQL Server, PostgreSQL or SQLite
using Cratis.Choreography.Storage;
builder.Services.AddCratisChoreographyInMemoryPatchStorage();

With CratisChoreographyOptions.Patching and Storage = GrainStorageMode.InMemory, the co-hosted silo registers it for you. Nothing survives the process, so every start applies every patch again.

using Cratis.Choreography.Setup;
using MongoDB.Driver;
builder.Services.AddCratisChoreographyMongoDBPatchStorage(
new MongoClient("mongodb://localhost:27017"),
options => options.DatabaseName = "choreography");

Records go to one database, choreography unless you change MongoDBPatchStorageOptions.DatabaseName:

CollectionDocument
patchesOne per applied patch, keyed by patch name, with version and appliedAt
patch-versionsA patched document and a host document, each with a version

Saving a patch that is already recorded replaces its document. A client registered earlier, for example by the jobs storage, is kept. More in MongoDB storage.

using Cratis.Choreography.Setup;
using Cratis.Choreography.Storage.Sql.Patching;
using Microsoft.EntityFrameworkCore;
builder.Services.AddCratisChoreographySqlPatchStorage(options =>
options.OptionsResolver = () =>
new DbContextOptionsBuilder<PatchesDbContext>()
.UseNpgsql("Host=localhost;Database=choreography;Username=app;Password=<password>")
.Options);

The resolver takes no arguments: unlike jobs storage it is not asked about a scope or namespace. The tables are Patches (Name, Version, AppliedAt) and PatchVersions (Id of patched or host, and Version). You do not create them; SqlPatchStorage applies its migration the first time it is used. More in SQL storage.

IPatchStorage keeps the applied patches plus two versions: the patched version (the newest patch applied) and the host version (the newest host with a known version that patched the store). The first stops a patch from running twice, the second stops an older host from patching a newer store. The overview explains how the manager uses them. If you write your own IPatchStorage, see the reference for the members.