Host the Choreography silo
A service that starts jobs needs an Orleans silo to run them. Cratis Choreography co-hosts that silo inside your ASP.NET Core application with one call, so you do not build an Orleans host and then wire the job system into it yourself.
Prerequisites
Section titled “Prerequisites”- The .NET SDK that matches the target framework of your application. The packages target .NET 8, 9 and 10.
- A MongoDB server, if you use MongoDB clustering, grain storage or jobs storage.
- A jobs storage registration, unless you host with in-memory storage. See Storage.
Host the silo
Section titled “Host the silo”using Cratis.Choreography.Hosting;using Cratis.Choreography.Setup;using MongoDB.Driver;
var builder = WebApplication.CreateBuilder(args);
builder.AddCratisChoreography(new CratisChoreographyOptions{ ClusterId = "my-service", ServiceId = "my-service"});
builder.Services.AddCratisChoreographyMongoDBJobsStorage( new MongoClient("mongodb://localhost:27017"));
var app = builder.Build();app.Run();AddCratisChoreography registers the serializers for Cratis types, the job, job step and jobs manager grains, their grain
storage providers, jobs recovery, the Orleans cluster identity and clustering. The storage call supplies the IJobsStorage
those providers read and write through; AddCratisChoreographyMongoDBJobsStorage lives in Cratis.Choreography.Setup, which is
why the sample imports it. Every option is listed in Options.
The jobs storage is resolved when the first job grain activates, not when the silo starts. A host that forgets it starts cleanly and fails on the first job.
Cluster on MongoDB
Section titled “Cluster on MongoDB”Out of the box the silo uses localhost clustering: one instance and no membership table. To run more than one instance, switch to durable MongoDB membership:
builder.AddCratisChoreography(new CratisChoreographyOptions{ ClusterId = "my-service", ServiceId = "my-service", Clustering = ClusteringMode.MongoDB, DatabaseName = "my-service-orleans", ConnectionString = builder.Configuration["Cratis:MongoDB:Server"]!});Run without a database
Section titled “Run without a database”A silo for development, tests or a runtime that hosts one silo does not need MongoDB. Keep grain state in memory and cluster on localhost:
builder.AddCratisChoreography(CratisChoreographyOptions.Local());With Storage = GrainStorageMode.InMemory, jobs, job steps and, with Workflows on, workflow runs live in the silo’s memory,
and nothing survives the process. The in-memory jobs storage is registered for you, so do not also call
AddCratisChoreographyMongoDBJobsStorage. With Patching on, the record of applied patches is kept in memory too.
Turn on workflows and patching
Section titled “Turn on workflows and patching”Both are off by default. Each flag takes an optional callback that configures its options:
builder.AddCratisChoreography(new CratisChoreographyOptions{ Workflows = true, ConfigureWorkflows = options => options.Scopes.Add("tenant-1"), Patching = true, ConfigurePatching = options => options.MaxAttempts = 8});Workflows hosts the workflow engine and registers the workflows grain storage provider.
Patching applies patches once per store when the silo becomes active. Unless you host with in-memory
storage, register a patch storage as well; starting a silo with Patching on and no IPatchStorage fails when the patch
manager grain activates. See Choose patch storage.
Tune the job system
Section titled “Tune the job system”JobsOptions properties are init-only, so assigning inside Configure does not compile. Register a constructed instance in the
service collection instead; AddCratisChoreography adds its defaults only when no IOptions<JobsOptions> is present, and your
registration wins whether it comes before or after the call:
using Cratis.Choreography.Jobs;using Microsoft.Extensions.Options;
builder.Services.AddSingleton(Options.Create(new JobsOptions{ MaxParallelSteps = 4, StepLeaseTimeout = TimeSpan.FromMinutes(2)}));Place controllers and workers, and carry tenants
Section titled “Place controllers and workers, and carry tenants”Dedicating silos to controlling jobs or performing steps is covered in Placement. Carrying your tenant context into grain calls is covered in Tenancy. Both are opt-in registrations on the silo builder.
Disable the silo
Section titled “Disable the silo”Pass Enabled = false, or bind it to configuration, and AddCratisChoreography returns without configuring anything. A spec
host can keep the registrations in its application and run without a silo.
Activity propagation
Section titled “Activity propagation”AddCratisChoreography calls AddActivityPropagation() for you, so trace context follows grain calls. If your host already
called it, the filters Choreography would add are skipped. Call it before AddCratisChoreography if you want it explicit:
called afterwards, Orleans registers the incoming and outgoing propagation filters a second time and every grain call produces
duplicate spans. That is how Microsoft.Orleans.Server 10.4.2, the version this package builds against, registers them. The tenant
travels in the Orleans RequestContext, not in activity baggage.
Observability
Section titled “Observability”- Logs. Choreography loggers use categories that start with
Cratis.Choreography. Raise that prefix toInformationto see job lifecycle decisions such as drains, retries and recovery passes;Debugadds each status change. Around their main operations, job and jobs manager grains open a log scope withScopeandNamespace(jobs addJobId), and step grains one withJobId,JobStepId,JobStepNameandJobStepStatus. Filter on those properties to follow one job. - Warnings worth alerting on.
Job watchdog failed,Job failed to persist new job status,Jobs recovery is incomplete,Failed to recover jobs for ...,Retrying jobs recovery ...andTransient storage error during .... The causes and fixes are in Troubleshooting. - Queries.
IJobsManageranswersGetJobs(JobQuery),GetJobsOfType<TJob, TRequest>()andGetAllJobs(). Get the manager for a scope and namespace withgrainFactory.GetJobsManager(scope, @namespace);JobQueryfilters by type, status and creation time and pages withSkipandTake(100 by default).JobState.Progresscarries the step counts.
using Cratis.Choreography.Jobs;using Cratis.Choreography.Storage.Jobs;
var manager = grainFactory.GetJobsManager("my-service", "tenant-1");var running = await manager.GetJobs(new JobQuery{ Statuses = [JobStatus.Running], Take = 20});Orleans package alignment
Section titled “Orleans package alignment”Every project that references Cratis.Choreography gets a Release-build check that fails when Microsoft.Orleans.Reminders
resolves to a different version than Microsoft.Orleans.Server. A mismatch builds in Debug and throws MissingMethodException
when the silo builds its grain services. Pin the Orleans packages to one version in Directory.Packages.props.
Next steps
Section titled “Next steps”- Reminders and recovery explains why reminders stay in memory and what recovery does on startup.
- Configure Orleans yourself shows the registrations when you build the silo without the helper.
- Hosting API lists every extension method.