Awesome
InfinityFlow.Aspire.Temporal
Aspire extension to start the temporal cli dev server as an container or executable resource. Note: Only container works as expected. See https://github.com/dotnet/aspire/issues/1637 and https://github.com/temporalio/cli/issues/316
Contents:
Pre-requisites
- Temporal CLI (ensure the binary is in your PATH)
- An Aspire project. See Aspire docs to get started.
Getting Started
1. Install the nuget package
dotnet add package InfinityFlow.Aspire.Temporal
2. Add Temporal dev server to your Aspire AppHost Program.cs
// AppHost/Program.cs
using Aspire.Temporal.Server;
var builder = DistributedApplication.CreateBuilder(args);
// Use the default server options
var temporal = await builder.AddTemporalServerContainer("temporal")
// OR customise server options with builder
// see config section for details
var temporal = await builder.AddTemporalServerContainer("temporal", x => x
.WithLogFormat(LogFormat.Json)
.WithLogLevel(LogLevel.Info)
.WithNamespace("test1", "test2"));
3. Run the Aspire application
You should see Temporal running under the Executables tab.
Temporal will be available on its default ports:
- Server: http://localhost:7233
- UI: http://localhost:8233
4. Configure Client/Worker Applications
The Temporal client can then be added to a .NET project as normal using the instructions from the temporal dotnet sdk repo
It can be included in Aspire orchestration like below and can optionally take a reference to the Temporal resource.
// ./samples/AppHost/Program.cs
// ...
var temporal = builder.AddTemporalServerExecutable("temporal");
builder.AddProject<Projects.Worker>("worker") // my custom project
.WithReference(temporal);
// ...
If using Temporalio.Extensions.Hosting the client registration might look something like below. If we took the reference to the Temporal Aspire resource, then the TargetHost property is automatically injected under the key ConnectionStrings:<Aspire Resource Name>
. (e.g., this will be builder.Configuration["ConnectionStrings:temporal"]
for a resource named "temporal" as above)
// register a client - ./samples/Api/Program.cs
builder.Services
.AddTemporalClient(opts =>
{
opts.TargetHost = builder.Configuration["ConnectionStrings:temporal"]; // or just self-configure localhost:7233
opts.Namespace = "default";
})
// or
// register a worker - ./samples/Worker/Program.cs
builder.Services
.AddTemporalClient(opts =>
{
opts.TargetHost = builder.Configuration["ConnectionStrings:temporal"]; // or just self-configure localhost:7233
opts.Namespace = "default";
})
.AddHostedTemporalWorker("my-task-queue")
.AddScopedActivities<MyActivities>()
.AddWorkflow<MyWorkflow>();
Observability
The extension doesn't provide any setup for observability, but you can follow Temporalio.Extensions.DiagnosticSource and Temporalio.Extensions.Hosting to configure this on the temporal client. If using the Aspire Service Defaults, you'll need to configure the metrics and tracing accordingly.
The sample folder has an example for configuring this with the Aspire Dashboard
- sample/Api/Program.cs for an example client
- sample/Worker/Program.cs for an example worker
- sample/ServiceDefaults/Extensions.cs for an example of adding the custom meter and tracing sources to the service defaults.
If done correctly, you should tracing and metrics on the Aspire dashboard:
Tracing
Metrics
Configuration
The dev server can be configured with a fluent builder
await builder.AddTemporalServerContainer("temporal", builder => builder.WithPort(1234))
You can run temporal server start-dev --help
to get more information about the CLI flags on the dev server. All available flags are mapped to a method on the builder.
Available methods:
builder
.WithDbFileName("/location/of/persistent/file") // --db-filename
.WithNamespace("namespace-name", ...) // --namespace
.WithPort(7233) // --port
.WithHttpPort(7234) // --http-port
.WithMetricsPort(7235) // --metrics-port
.UiPort(8233) // --ui-port
.WithHeadlessUi(true) // --headless
.WithIp("127.0.0.1") // --ip
.WithUiIp("127.0.0.1") // --ui-ip
.WithUiAssetPath("/location/of/custom/assets") // --ui-asset-path
.WithUiCodecEndpoint("http://localhost:8080") // --ui-codec-endpoint
.WithLogFormat(LogFormat.Pretty) // --log-format
.WithLogLevel(LogLevel.Info) // --log-level
.WithSQLitePragma(SQLitePragma.JournalMode) // --sqlite-pragma