Skip to content

Wangbill/serverless private preview op1#734

Draft
YunchuWang wants to merge 43 commits into
mainfrom
wangbill/serverless-private-preview-op1
Draft

Wangbill/serverless private preview op1#734
YunchuWang wants to merge 43 commits into
mainfrom
wangbill/serverless-private-preview-op1

Conversation

@YunchuWang
Copy link
Copy Markdown
Member

Summary

What changed?

Why is this change needed?

Issues / work items

  • Resolves #
  • Related #

Project checklist

  • Release notes are not required for the next release
    • Otherwise: Notes added to release_notes.md
  • Backport is not required
    • Otherwise: Backport tracked by issue/PR #issue_or_pr
  • All required tests have been added/updated (unit tests, E2E tests)
  • Breaking change?
    • If yes:
      • Impact:
      • Migration guidance:

AI-assisted code disclosure (required)

Was an AI tool used? (select one)

  • No
  • Yes, AI helped write parts of this PR (e.g., GitHub Copilot)
  • Yes, an AI agent generated most of this PR

If AI was used:

  • Tool(s):
  • AI-assisted areas/files:
  • What you changed after AI output:

AI verification (required if AI was used):

  • I understand the code and can explain it
  • I verified referenced APIs/types exist and are correct
  • I reviewed edge cases/failure paths (timeouts, retries, cancellation, exceptions)
  • I reviewed concurrency/async behavior
  • I checked for unintended breaking or behavior changes

Testing

Automated tests

  • Result: Passed / Failed (link logs if failed)

Manual validation (only if runtime/behavior changed)

  • Environment (OS, .NET version, components):
  • Steps + observed results:
    1.
    2.
    3.
  • Evidence (optional):

Notes for reviewers

  • N/A

YunchuWang added 30 commits May 13, 2026 19:29
ServerlessActivitiesClientAdapter now takes an attachTaskHubMetadata flag (default true). The Azure-managed channel already injects the taskhub header via CallCredentials, so the AddDurableTaskScheduler* path constructs the adapter with attachTaskHubMetadata: false to avoid sending duplicate headers on DeclareServerlessActivities and ConnectServerlessActivityWorker. Added two unit tests with a recording CallInvoker covering both modes.
This reverts commit 18c8e02.
- Updated README.md to clarify remote worker image settings.
- Simplified task hub retrieval in Program.cs.
- Removed unnecessary endpoint configuration in remote worker.
- Added Azure.Identity package reference in csproj.
- Refined serverless worker extensions for environment configuration.
- Updated serverless activity configuration to handle registered activities.
- Modified tests to reflect changes in activity registration and filtering.
Comment on lines +224 to +230
foreach (string? value in values)
{
if (!string.IsNullOrWhiteSpace(value))
{
return value.Trim();
}
}
Comment on lines +224 to +229
catch (Exception ex)
{
Logs.ServerlessActivityWorkerRegistrationFailed(this.logger, ex, this.options.TaskHub);
await this.DelayBeforeReconnectAsync(retryDelay, cancellationToken).ConfigureAwait(false);
retryDelay = this.GetNextRetryDelay(retryDelay);
}
Comment on lines +260 to +263
catch (Exception)
{
// The server response is authoritative once the response task wins the race.
}
Comment on lines +109 to +111
catch (Exception ex) when (ex is OperationCanceledException or ObjectDisposedException or RpcException)
{
}
Comment on lines +120 to +122
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
}
Comment on lines +123 to +125
catch (Exception ex) when (ex is OperationCanceledException or ObjectDisposedException or RpcException)
{
}
Comment on lines +176 to +178
catch (Exception ex) when (ex is OperationCanceledException or ObjectDisposedException or RpcException)
{
}
Comment on lines +257 to +259
catch (OperationCanceledException) when (heartbeatCts.IsCancellationRequested)
{
}
{
public override async Task<string> RunAsync(TaskOrchestrationContext context, string input)
{
string remoteResult = await context.CallActivityAsync<string>(ServerlessTaskNames.RemoteHello, input);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: return directly

Comment thread samples/serverless/main-app/Program.cs Outdated
using Microsoft.Extensions.Logging;

string endpoint = GetRequiredEnvironmentVariable("DTS_ENDPOINT");
string taskHub = Environment.GetEnvironmentVariable("DTS_TASK_HUB") ?? "ServerlessPocHub";
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better way to populate these values nicely and cleanly than env var?

TokenCredential credential = new DefaultAzureCredential();

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddSimpleConsole(options =>
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why add this console? we really need this?

Comment thread samples/serverless/main-app/Program.cs Outdated

await host.StopAsync();

static string GetRequiredEnvironmentVariable(string name)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be cleaner if we can remove these if not using env var

Comment thread samples/serverless/main-app/Program.cs Outdated
: throw new InvalidOperationException($"Environment variable '{name}' must be a positive integer.");
}

static string ParseHelloInput(string[] args, string defaultHelloInput)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hello input dont need to be passed in, to make sample cleaner just use some random hardcoded values

Introduce annotation-driven serverless activity declarations and related plumbing. Add ServerlessWorkerProfileAttribute, ServerlessActivityAttribute, IServerlessWorkerProfile, and ServerlessActivityAnnotationResolver to discover profiles and activity markers in loaded assemblies. Replace DeclareServerlessActivities(configure) with EnableServerlessActivities(), change exclusion filter to use annotated activity names, and update scheduler wiring to configure endpoint/task hub without DefaultAzureCredential. Update ServerlessActivityDeclarationHostedService to accept and declare multiple ServerlessOptions. Update samples: add worker profile, declaration markers, many orchestrators and remote activity implementations, demo command parsing, and a skip-declaration flag. Extend tests to validate annotation resolution, hosted service registration, and worker runtime option behavior.
Rework the serverless sample to simplify activities and configuration. Move DefaultServerlessWorkerProfile into a new main-app/WorkerProfiles.cs and update README to reference it. Rename LocalEcho to LocalHello and change its output format; have the HelloOrchestrator call the local activity and concatenate local and remote results. Simplify main-app Program: streamline input handling, always enable serverless activities, and directly schedule the Hello orchestrator. Trim remote worker to a single RemoteHello activity that returns the scheduler-injected marker from env, and update the remote worker Program to only register that activity.
Replace ResolveActivityNames implementation to scan attribute-decorated types instead of relying on Resolve(taskHub). The new logic collects declared worker profiles, ensures profiles are unique, validates that activities reference declared profiles, and prevents the same activity name from being assigned to multiple profiles. Added unit test to assert ResolveActivityNames can run without triggering profile Configure calls and updated the annotated test profile with a ConfigureCallCount to verify no configure invocation occurs.
Add a runtime guard that throws when EnableServerlessActivities is called in a DTS serverless worker (DTS_SUBSTRATE == "Sandbox" or "AcaSessionPool"). Introduces a constant error message and ThrowIfServerlessWorkerRuntime, extracts IsServerlessWorkerSubstrate helper, and updates substrate-based mode detection to use it. Adds a unit test to verify the method throws and does not register hosted services when running in the serverless worker substrate.
Introduce a cached annotation catalog and centralize task-name resolution. ServerlessActivityAnnotationResolver now exposes ResolveDeclarations and uses a Lazy-scanned AnnotationCatalog (ProfileMetadata/ActivityMetadata) via ScanAnnotations to collect and validate profiles/activities, preventing duplicate scans and improving clarity. Extract DurableTask name logic into a new ServerlessTaskNameResolver and update ServerlessOptions.AddActivity and activity-name resolution to use it. Update DurableTaskSchedulerServerlessWorkerExtensions and tests to call the new ResolveDeclarations API.
Make serverless activity resolution task-hub aware and validate ownership. ServerlessActivityAnnotationResolver now resolves declarations per task hub, builds profile options, validates that an activity name isn't assigned to multiple profiles, and exposes ResolveDeclaredActivityNames. DurableTaskSchedulerServerlessWorkerExtensions uses the task-hub-specific declarations to exclude remote activities from local execution. ServerlessActivityAttribute docs updated to clarify Name is optional and resolution rules. Samples updated to register declared activities via IServerlessWorkerProfile.Configure (and remove marker declaration), and tests updated to reflect the new resolution and validation behavior.
Add appsettings.json to store scheduler endpoint and task hub (ServerlessSample:EndpointAddress/TaskHubName) and update README with instructions to run the sample. Program.cs now reads configuration from builder.Configuration, uses a constant input, and removes the GetRequiredEnvironmentVariable helper. WorkerProfiles no longer sets the SERVERLESS_SAMPLE_MARKER env var, and the remote activity stops reading/echoing the marker. Expected output in the README was updated to match the new activity output.
Inline the logic previously in ServerlessTaskNameResolver into ServerlessActivityAnnotationResolver and ServerlessOptions, and delete the now-unused ServerlessTaskNameResolver.cs. Both locations now resolve task names by checking for a DurableTaskAttribute (using DurableTaskAttribute.Name.Name when present and non-empty) and falling back to the type's Name; ServerlessOptions also adds a GetTaskName helper and a null check. This reduces indirection and removes the obsolete helper class.
YunchuWang and others added 4 commits May 27, 2026 12:07
Rename ServerlessActivityAnnotationResolver to ServerlessActivityDeclarationResolver and update references accordingly. Remove the ServerlessActivityAttribute type and adjust the resolver to scan worker profiles (Configure) for declarations instead of activity annotations. Update DurableTaskSchedulerServerlessWorkerExtensions to call the new resolver and modify tests to expect only profile-configured activities. This simplifies the serverless activity declaration model to rely on worker profile configuration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment on lines +272 to +278
foreach (DurableTaskWorkerWorkItemFilters.ActivityFilter filter in existingFilters)
{
if (!string.IsNullOrWhiteSpace(filter.Name))
{
merged[filter.Name] = filter;
}
}
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