Skip to content

v1.0 API redesign: annotation-based config, client library, and OTel integration#273

Closed
ElanHasson wants to merge 2 commits intoInfinityFlowApp:mainfrom
ElanHasson:feature/dynamic-port-allocation
Closed

v1.0 API redesign: annotation-based config, client library, and OTel integration#273
ElanHasson wants to merge 2 commits intoInfinityFlowApp:mainfrom
ElanHasson:feature/dynamic-port-allocation

Conversation

@ElanHasson
Copy link
Copy Markdown
Contributor

@ElanHasson ElanHasson commented Jan 25, 2026

Summary

Complete v1.0 API redesign of InfinityFlow.Aspire.Temporal:

  • Annotation-based configuration replacing the old lambda callback builder pattern
  • New client library (InfinityFlow.Aspire.Temporal.Client) with AddTemporalClient, AddTemporalWorker, health checks, and automatic OpenTelemetry
  • OTel export from the Temporal container to the Aspire dashboard
  • All 18 temporal server start-dev CLI flags supported
  • 95 tests (84 unit + 11 integration with real Aspire hosts)

Breaking Changes

Hosting API

Before (lambda callback):

builder.AddTemporalServerContainer("temporal", x => x
    .WithPort(7233)
    .WithLogFormat(LogFormat.Json)
    .WithNamespace("ns1"));

After (fluent extension methods):

builder.AddTemporalServerContainer("temporal")
    .WithServicePort(7233)
    .WithLogFormat(LogFormat.Json)
    .WithNamespace("ns1");
  • TemporalServerResourceBuilder and TemporalServerResourceArguments removed
  • Configuration now stored as Aspire annotations on the resource
  • CLI args built dynamically from annotations via TemporalServerArgsBuilder

New Client Library

// Worker project
builder.AddTemporalWorker("temporal", "my-task-queue", opts =>
{
    opts.Namespace = "my-namespace";
})
.AddWorkflow<MyWorkflow>()
.AddScopedActivities<MyActivities>();

// API project
builder.AddTemporalClient("temporal", opts =>
{
    opts.Namespace = "my-namespace";
});

// Service defaults
builder.Services.AddTemporalServiceDefaults();

Both methods automatically resolve connection strings, add TracingInterceptor, configure CustomMetricMeter, and register health checks.

Architecture

Configuration is now stored as IResourceAnnotation types:

  • TemporalNamespaceAnnotation, TemporalLogFormatAnnotation, TemporalLogLevelAnnotation, etc.
  • TemporalServerArgsBuilder reads all annotations and builds CLI args
  • ITemporalServerResource interface shared by container and executable resources

Configuration Reference

All temporal server start-dev flags are supported:

builder.AddTemporalServerContainer("temporal")
    .WithDbFileName("/path/to/db")           // --db-filename
    .WithNamespace("ns1", "ns2")             // --namespace
    .WithServicePort(7233)                   // --port
    .WithHttpPort()                          // --http-port
    .WithMetricsEndpoint()                   // --metrics-port
    .WithUiPort(8233)                        // --ui-port
    .WithHeadlessUi()                        // --headless
    .WithIp("127.0.0.1")                     // --ip
    .WithUiIp("127.0.0.1")                   // --ui-ip
    .WithUiAssetPath("/path")                // --ui-asset-path
    .WithUiCodecEndpoint("http://...")        // --ui-codec-endpoint
    .WithUiPublicPath("/temporal")           // --ui-public-path
    .WithLogFormat(LogFormat.Pretty)         // --log-format
    .WithLogLevel(LogLevel.Info)             // --log-level
    .WithLogConfig(true)                     // --log-config
    .WithSQLitePragma(SQLitePragma.JournalMode) // --sqlite-pragma
    .WithDynamicConfigValue("key", value)    // --dynamic-config-value
    .WithSearchAttribute("Key", SearchAttributeType.Keyword) // --search-attribute
    .WithImageTag("latest");                 // custom image tag

Other Changes

  • Docker image updated to temporalio/admin-tools:1.30.1
  • .WithOtlpExporter() added to container resource for Aspire dashboard telemetry
  • Package version bumped to 1.0.0
  • Sample apps updated to new API
  • Dependency versions updated (Aspire 13.1.2, Temporalio 1.9.0)

Test Plan

  • 84 unit tests covering annotations, args builder, fluent API, endpoints, client extensions
  • 2 integration tests: search attributes and namespace creation via Temporal APIs
  • 9 client library integration tests: AddTemporalClient, AddTemporalWorker (scoped/transient/singleton/instance activities), ConfigureOptions, health check, end-to-end workflow execution
  • All tests run against real Temporal dev server containers via Aspire hosting
Passed! - Failed: 0, Passed: 95, Skipped: 0

Generated with Claude Code

BREAKING CHANGE: Default port allocation changed from fixed to dynamic

## Changes

### Core API (Breaking)
- Changed `Port` property from `int` to `int?` in TemporalServerResourceArguments
- Removed default values (7233, 8233) to enable dynamic allocation
- Updated container extension to use fixed `targetPort` with dynamic `port`
- Removed fallback port calculations in executable extension
- Updated builder methods to accept nullable port parameters

### Client Integration Library (New)
- Added InfinityFlow.Aspire.Temporal.Client package
- Provides `AddTemporalClient()` and `AddTemporalWorker()` extension methods
- Automatic connection string resolution from Aspire configuration
- Follows standard Aspire client integration patterns

### Documentation
- Updated README with breaking changes section
- Added migration guide from v0.x to v1.0
- Updated sample to demonstrate both dynamic and fixed port usage
- Improved connection string documentation

### Tests
- Added comprehensive unit tests for port allocation
- Tests verify both dynamic and fixed port scenarios
- All 7 tests passing

## Benefits
- Eliminates port conflicts in multi-instance scenarios
- Better parallel test execution
- Consistent with official Aspire networking patterns
- Easier client integration with new library

## Migration
To maintain v0.x behavior with fixed ports:
```csharp
var temporal = builder.AddTemporalServerContainer("temporal", x => x
    .WithPort(7233)
    .WithUiPort(8233));
```

Follows patterns from:
- https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/networking-overview
- Aspire.Hosting.PostgreSQL
- Aspire.Hosting.Valkey

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@ElanHasson ElanHasson force-pushed the feature/dynamic-port-allocation branch from 3bc0bc3 to 7d93d3f Compare January 25, 2026 22:48
@ElanHasson ElanHasson changed the title feat: Add dynamic port allocation following Aspire patterns feat: Simplified Temporal API with dynamic ports, fluent builder, and critical fixes Jan 25, 2026
@ElanHasson ElanHasson changed the title feat: Simplified Temporal API with dynamic ports, fluent builder, and critical fixes v1.0 API redesign: annotation-based config, client library, and OTel integration Mar 7, 2026
@ElanHasson
Copy link
Copy Markdown
Contributor Author

Code review

Found 1 issue:

  1. Container targetPort hardcoded to fixed values breaks custom port configuration. When a user sets a custom port via WithPort(5555) or WithServiceEndpoint(12345), the CLI arg --port 5555 tells the Temporal process inside the container to listen on port 5555. But targetPort is hardcoded to 7233, so Docker forwards traffic to container port 7233 where nothing is listening. The same applies to UI (8233), metrics (7235), and HTTP (7234) ports. The fix should use the user-specified value when present, e.g. targetPort: args.Port ?? 7233. Both AddTemporalServerContainer and the new BuildContainer() in TemporalResourceBuilder have this bug. The PR's own sample demonstrates custom ports (WithServiceEndpoint(12345)) which would be broken.

https://github.com/InfinityFlowApp/aspire-temporal/blob/252fb2fc6bdca05211cdf32b76509e885323f523/src/InfinityFlow.Aspire.Temporal/TemporalServerContainerBuilderExtensions.cs#L49-L65

https://github.com/InfinityFlowApp/aspire-temporal/blob/252fb2fc6bdca05211cdf32b76509e885323f523/src/InfinityFlow.Aspire.Temporal/TemporalBuilderExtensions.cs#L353-L369

Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant