-
Notifications
You must be signed in to change notification settings - Fork 42
Add sample Temporal integration for Aspire #127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b5bf216
d89d4bc
ff59b4f
b45ba00
cae22a7
12a9874
ff4cabc
344ac89
fde2522
25dab66
1c0a34f
37d7c6e
b0a250c
bba7770
7f23e39
fe60f45
a49a80f
17b2151
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,277 @@ | ||
| # Temporal Extensions for .NET Aspire | ||
|
|
||
| ## Overview | ||
|
|
||
| This project provides custom Aspire resource definitions that enable developers to integrate Temporal workflow servers into their Aspire applications with minimal configuration. It supports three deployment models: | ||
|
|
||
| - **Local Testing** - Temporal server using `Temporalio.Testing.WorkflowEnvironment` for fast local development and testing | ||
| - **Container-based** - Docker container running the official Temporal server image for development and staging environments | ||
| - **CLI-based** - Temporal CLI server for environments where Docker isn't available | ||
|
|
||
| ### Key Features | ||
|
|
||
| - ✅ **Service Discovery** - Automatic environment variable injection for dependent services | ||
| - ✅ **Health Checks** - Built-in health checks integrated into Aspire's health pipeline | ||
| - ✅ **Resource Management** - Start/Stop commands in the Aspire dashboard with proper state management | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| ### Required | ||
| - **[.NET SDK](https://dot.net)** 8.0 or later | ||
| - **[Aspire tooling](https://learn.microsoft.com/dotnet/aspire/fundamentals/setup-tooling)** 13.0 or later | ||
|
|
||
| ### For Container-based Setup | ||
| - **Docker** - Required to run the Temporal container | ||
| - **Docker image** - `temporalio/temporal:latest` (automatically pulled) | ||
|
|
||
| ### For CLI-based Setup | ||
| - **Temporal CLI** - Install via [Temporal CLI documentation](https://docs.temporal.io/cli/install) | ||
|
|
||
| ## Running the Project | ||
|
|
||
| Using the Aspire CLI | ||
|
|
||
| 1. **Navigate to the AppHost project directory:** | ||
| ```bash | ||
| cd src/AspireIntegrations/ | ||
| ``` | ||
|
|
||
| 2. **Run the project using the Aspire CLI:** | ||
| ```bash | ||
| aspire run | ||
| ``` | ||
|
|
||
| > You can also run the project directly with `dotnet run` from the AppHost directory, or use your IDE's run configuration. | ||
|
|
||
| ## Setup Options | ||
|
|
||
| ### Local Server | ||
|
|
||
| The local server setup uses a Temporal environment for fast testing without external dependencies. It will download and run the necessary Temporal server binaries. | ||
|
|
||
| **AppHost.cs:** | ||
| ```csharp | ||
| using Temporal.Extensions.Aspire.Hosting; | ||
|
|
||
| var builder = DistributedApplication.CreateBuilder(args); | ||
|
|
||
| // Add Temporal local server | ||
| var temporal = builder.AddTemporalLocalDevServer(); | ||
|
|
||
| // Add a worker project that depends on Temporal | ||
| builder.AddProject<Projects.TemporalioSamples_SampleWorker>("worker") | ||
| .WaitFor(temporal) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we do this automatically for them in the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's an Apsire pattern that I've wondered about in general. It should be fine
Copilot marked this conversation as resolved.
|
||
| .WithReference(temporal); | ||
|
|
||
| builder.Build().Run(); | ||
|
cecilphillip marked this conversation as resolved.
|
||
| ``` | ||
|
|
||
| **Advanced Configuration:** | ||
| ```csharp | ||
| var temporal = builder.AddTemporalLocalDevServer(configure: options => | ||
| { | ||
| // Port configuration | ||
| options.UIPort = 8233; // Web UI port | ||
| options.MetricsPort = 9233; // Metrics endpoint port | ||
|
|
||
| // Network binding | ||
| options.TargetHost = "0.0.0.0:7233"; | ||
|
|
||
| // Namespace configuration | ||
| options.Namespace = "default"; | ||
| options.AdditionalNamespaces = ["orders", "analytics"]; | ||
|
|
||
| // Use existing Temporal server binary | ||
| options.DevServerOptions.ExistingPath = "/usr/local/bin/temporal"; | ||
|
|
||
| // UI configuration | ||
| options.UI = true; | ||
|
|
||
| // Search attributes for custom workflows | ||
| options.SearchAttributes = new[] | ||
| { | ||
| new SearchAttribute { Name = "Environment", ValueType = "Text" }, | ||
| new SearchAttribute { Name = "UserId", ValueType = "Text" }, | ||
| new SearchAttribute { Name = "ProcessingTime", ValueType = "Int" } | ||
| }; | ||
|
|
||
| // Dynamic configuration values | ||
| options.DynamicConfigValues = [ | ||
| "persistence.cassandra.hosts = cassandra-host:9042" | ||
| ]; | ||
|
cecilphillip marked this conversation as resolved.
|
||
| }); | ||
| ``` | ||
|
|
||
| > Use `ExistingPath` to leverage a pre-installed Temporal binary | ||
|
|
||
| --- | ||
|
|
||
| ### Container-based | ||
|
|
||
| Deploy Temporal using the CLI Docker container. | ||
|
|
||
| **AppHost.cs:** | ||
| ```csharp | ||
| using Temporal.Extensions.Aspire.Hosting; | ||
|
|
||
| var builder = DistributedApplication.CreateBuilder(args); | ||
|
|
||
| // Add Temporal as a Docker container | ||
| var temporal = builder.AddTemporalDevContainer( | ||
| configure: options => | ||
| { | ||
| options.ImageTag = "latest"; // Use specific version if needed | ||
| options.UI = true; // Enable Web UI | ||
| options.Namespace = "default"; | ||
| }); | ||
|
|
||
| // Add dependent projects that require Temporal | ||
| builder.AddProject<Projects.TemporalioSamples_SampleWorker>("worker") | ||
| .WaitFor(temporal) | ||
|
Copilot marked this conversation as resolved.
|
||
| .WithReference(temporal); | ||
|
|
||
| builder.Build().Run(); | ||
| ``` | ||
|
|
||
| **Advanced Configuration:** | ||
| ```csharp | ||
| var temporal = builder.AddTemporalDevContainer(configure: options => | ||
| { | ||
| // Network configuration | ||
| options.TargetHost = "127.0.0.1:7233"; | ||
|
|
||
| // Namespaces | ||
| options.AdditionalNamespaces = ["default", "custom-ns"]; | ||
|
|
||
| // Logging | ||
| options.DevServerOptions.LogLevel = "info"; | ||
| options.DevServerOptions.LogFormat = "json"; | ||
|
|
||
| // Search attributes for custom workflows | ||
| options.SearchAttributes = new[] | ||
| { | ||
| new SearchAttribute { Name = "CustomField", ValueType = "Text" }, | ||
| new SearchAttribute { Name = "CustomInt", ValueType = "Int" } | ||
| }; | ||
| }); | ||
| ``` | ||
| --- | ||
|
|
||
| ### CLI-based | ||
|
|
||
| Use the Temporal CLI server for environments without Docker. | ||
|
|
||
| **AppHost.cs:** | ||
| ```csharp | ||
| using Temporal.Extensions.Aspire.Hosting; | ||
|
|
||
| var builder = DistributedApplication.CreateBuilder(args); | ||
|
|
||
| // Add Temporal CLI server | ||
| var temporal = builder.AddTemporalCliServer( | ||
| configure: options => | ||
| { | ||
| options.Namespace = "default"; | ||
| options.UI = true; | ||
| }); | ||
|
|
||
| // Add dependent projects that require Temporal | ||
| builder.AddProject<Projects.TemporalioSamples_SampleWorker>("worker") | ||
| .WaitFor(temporal) | ||
|
Copilot marked this conversation as resolved.
|
||
| .WithReference(temporal); | ||
|
|
||
| builder.Build().Run(); | ||
| ``` | ||
|
|
||
| **Advanced Configuration:** | ||
| ```csharp | ||
| var temporal = builder.AddTemporalCliServer(configure: options => | ||
| { | ||
| // Port configuration | ||
| options.UIPort = 8233; // Web UI port | ||
| options.MetricsPort = 9233; // Metrics endpoint port | ||
|
|
||
| // Network binding | ||
| options.TargetHost = "0.0.0.0:7233"; | ||
|
|
||
| // Namespace configuration | ||
| options.Namespace = "default"; | ||
| options.AdditionalNamespaces = ["orders", "analytics"]; | ||
|
|
||
| // UI configuration | ||
| options.UI = true; | ||
|
|
||
| // Search attributes for custom workflows | ||
| options.SearchAttributes = new[] | ||
| { | ||
| new SearchAttribute { Name = "Environment", ValueType = "Text" }, | ||
| new SearchAttribute { Name = "UserId", ValueType = "Text" }, | ||
| new SearchAttribute { Name = "ProcessingTime", ValueType = "Int" } | ||
| }; | ||
|
|
||
| // Dynamic configuration values | ||
| options.DynamicConfigValues = [ | ||
| "persistence.cassandra.hosts = cassandra-host:9042" | ||
| ]; | ||
| }); | ||
| ``` | ||
|
|
||
| **Requirements:** | ||
| - Temporal CLI must be installed and available in PATH | ||
| - Run `temporal --version` to verify installation | ||
| --- | ||
|
|
||
| ### Connection Strings | ||
|
|
||
| Dependent projects receive the following environment variables automatically: | ||
|
|
||
| | Variable | Description | | ||
| |----------|-------------| | ||
| | `TEMPORAL_ADDRESS` | The gRPC server address (e.g., `localhost:7233` or container name:port) | | ||
| | `TEMPORAL_UI_ADDRESS` | The Web UI address (e.g., `http://localhost:8233`) | | ||
| | `TEMPORAL_NAMESPACE` | The namespace to use (matches the resource's configured namespace) | | ||
| | `TEMPORAL_CODEC_AUTH` | Optional codec authentication token (if configured) | | ||
| | `TEMPORAL_CODEC_ENDPOINT` | Optional codec server endpoint (if configured) | | ||
|
|
||
| **Example usage:** | ||
| ```csharp | ||
| var temporalAddress = Environment.GetEnvironmentVariable("TEMPORAL_ADDRESS"); | ||
| var temporalUiAddress = Environment.GetEnvironmentVariable("TEMPORAL_UI_ADDRESS"); | ||
| var temporalNamespace = Environment.GetEnvironmentVariable("TEMPORAL_NAMESPACE") ?? "default"; | ||
| ``` | ||
| --- | ||
|
|
||
| ## Configuration Options | ||
|
|
||
| ### TemporalResourceOptions | ||
|
|
||
| The base configuration class for all resource types: | ||
|
|
||
| | Option | Type | Default | Description | | ||
| |--------|------|---------|-------------| | ||
| | `Namespace` | string | "default" | Primary namespace for workflows | | ||
| | `AdditionalNamespaces` | List<string> | ["default"] | Additional namespaces to register | | ||
| | `Port` | int | 7233 | gRPC service port | | ||
| | `UIPort` | int | 8233 | Web UI port | | ||
| | `MetricsPort` | int | 9233 | Metrics endpoint port | | ||
| | `UI` | bool | true | Enable Web UI | | ||
| | `TargetHost` | string | "0.0.0.0:7233" | Bind address (IP:port format) | | ||
| | `SearchAttributes` | List<SearchAttribute> | null | Custom search attributes | | ||
| | `DynamicConfigValues` | List<string> | [] | Dynamic configuration | | ||
| | `CodecEndpoint` | string | null | Codec server endpoint | | ||
| | `CodecAuth` | string | null | Codec authentication token | | ||
|
|
||
| ### Container-specific Options | ||
|
|
||
| | Option | Type | Default | Description | | ||
| |--------|------|---------|-------------| | ||
| | `ImageTag` | string | "latest" | Docker image tag version | | ||
|
|
||
| --- | ||
|
|
||
| ## Resources | ||
|
|
||
| - [Temporal Documentation](https://docs.temporal.io/) | ||
| - [Temporal .NET SDK](https://github.com/temporalio/sdk-dotnet) | ||
| - [.NET Aspire](https://learn.microsoft.com/dotnet/aspire) | ||
| - [Aspire Integrations](https://learn.microsoft.com/dotnet/aspire/integrations) | ||
Uh oh!
There was an error while loading. Please reload this page.