-
Notifications
You must be signed in to change notification settings - Fork 55
Support CallHttpAsync in Standalone SDK #696
Description
Support built in CallHttpAsync in Standalone SDK
Summary
Add built-in BuiltIn::HttpActivity support to the standalone worker SDK (Microsoft.DurableTask.Worker) so that CallHttpAsync works when using durabletask-dotnet to connect to sidecar (e.g.,, azuremanaged backend).
Today, CallHttpAsync only works when the Azure Functions Durable Task extension host is present, because the host intercepts the BuiltIn::HttpActivity task in TaskHttpActivityShim before it reaches the worker. In standalone mode, the activity dispatches to the worker, which has no registration for it and fails with a non-retriable ActivityTaskNotFound error.
Motivation
The standalone SDK (Microsoft.DurableTask.Client + Microsoft.DurableTask.Worker) is increasingly used outside Azure Functions — with , Dapr Workflow, and dts backend. HTTP calls are one of the most common orchestration primitives. Requiring users to hand-roll their own HTTP activity to achieve what CallHttpAsync provides out of the box in Azure Functions creates an unnecessary capability gap.
Current behavior (standalone + dts backend)
// This compiles only if you reference Worker.Extensions.DurableTask (Azure Functions package)
// and fails at runtime because nobody handles the built-in activity:
var response = await context.CallHttpAsync(new DurableHttpRequest(HttpMethod.Get, new Uri("https://example.com")));
// → TaskFailedException: ActivityTaskNotFound — "No activity task named 'BuiltIn::HttpActivity' was found."Even calling it manually without the extension method produces the same failure:
await context.CallActivityAsync<DurableHttpResponse>("BuiltIn::HttpActivity", request);
// → same ActivityTaskNotFound errorExpected behavior
CallHttpAsync (or an equivalent API) should work out of the box with any backend, not just Azure Functions.
Proposed Design
Auto-register a built-in HTTP activity implementation inside DurableTaskWorker that executes the HTTP call locally using HttpClient. This mirrors the approach used by TaskHttpActivityShim in the Functions host, but lives in the SDK itself.
Key changes
-
New internal class
BuiltInHttpActivityinMicrosoft.DurableTask.Worker— implementsITaskActivity, usesHttpClientto execute theDurableHttpRequestand return aDurableHttpResponse. -
Auto-registration in
DurableTaskWorkerBuilder.Build()— injectBuiltInHttpActivityfor the name"BuiltIn::HttpActivity"unless the user has explicitly registered their own activity with that name. -
Move
CallHttpAsyncextension method and HTTP types to the core SDK — theCallHttpAsyncextension method,DurableHttpRequest, andDurableHttpResponsecurrently live in the Azure Functions extension package. They should be available to standalone SDK users without requiring a dependency onWorker.Extensions.DurableTask. -
User override — if a user registers their own
"BuiltIn::HttpActivity"factory, the auto-registration yields to the user's implementation.
What to support in v1
| Feature | Support | Notes |
|---|---|---|
| HTTP methods (GET/POST/PUT/DELETE/PATCH) | Yes | Core functionality |
| Custom headers | Yes | Passed through to HttpRequestMessage |
| Request body | Yes | String content |
| Response status + headers + body | Yes | Mapped to DurableHttpResponse |
| Timeout | Yes | From DurableHttpRequest.Timeout |
AsynchronousPatternEnabled (202 polling) |
No (v2) | Complex loop — return 202 as-is with a log warning |
TokenSource / Managed Identity |
No (v2) | Requires Azure.Identity dependency |
HttpRetryOptions |
No (v2) | Durable Task already supports retries via TaskOptions at the activity level |
Architecture
Orchestrator → CallHttpAsync(request)
→ CallActivityAsync("BuiltIn::HttpActivity", request)
→ sidecar dispatches to worker
→ DurableTaskWorker activity lookup
→ BuiltInHttpActivity.RunAsync()
→ HttpClient.SendAsync(...)
→ return DurableHttpResponse
This is the same flow as any user-defined activity, except the SDK pre-registers it.
Alternatives Considered
-
Document "just write your own HTTP activity" — shifts burden to every standalone user. Boilerplate for a universal primitive.
-
Move it to a separate NuGet package (
Microsoft.DurableTask.Worker.Http) — possible but adds packaging overhead for a feature that should be first-class.
Additional Context
- The Java SDK (
durabletask-java) has the same gap —DurableHttp.callHttp()schedulesBuiltIn::HttpActivitybut the standalone worker has no handler. A parallel enhancement is being proposed there. - The Python SDK (
durabletask-python) would benefit from the same pattern.