internal async Task <bool> ScheduleDurableTaskEvents(OrchestrationInvocationResult result) { var execution = result.Json.ToObject <OutOfProcOrchestratorState>(); if (execution.CustomStatus != null) { this.context.SetCustomStatus(execution.CustomStatus); } await this.ReplayOOProcOrchestration(execution.Actions, execution.SchemaVersion); if (!string.IsNullOrEmpty(execution.Error)) { string exceptionDetails = $"Message: {execution.Error}, StackTrace: {result.Exception.StackTrace}"; throw new OrchestrationFailureException( $"Orchestrator function '{this.context.Name}' failed: {execution.Error}", exceptionDetails); } if (execution.IsDone) { this.context.SetOutput(execution.Output); return(false); } // there are more executions to process return(true); }
public async Task CallHttpActionOrchestrationWithManagedIdentityOptions() { DurableHttpRequest request = null; // Mock the CallHttpAsync API so we can capture the request and return a fixed response. var contextMock = new Mock <IDurableOrchestrationContext>(); contextMock .Setup(ctx => ctx.CallHttpAsync(It.IsAny <DurableHttpRequest>())) .Callback <DurableHttpRequest>(req => request = req) .Returns(Task.FromResult(new DurableHttpResponse(System.Net.HttpStatusCode.OK))); var shim = new OutOfProcOrchestrationShim(contextMock.Object); var executionJson = @" { ""isDone"": false, ""actions"": [ [{ ""actionType"": ""CallHttp"", ""httpRequest"": { ""method"": ""GET"", ""uri"": ""https://example.com"", ""tokenSource"": { ""kind"": ""AzureManagedIdentity"", ""resource"": ""https://management.core.windows.net/.default"", ""options"": { ""authorityhost"": ""https://login.microsoftonline.com/"", ""tenantid"": ""example_tenant_id"" } } } }] ] }"; // Feed the out-of-proc execution result JSON to the out-of-proc shim. var jsonObject = JObject.Parse(executionJson); OrchestrationInvocationResult result = new OrchestrationInvocationResult() { ReturnValue = jsonObject, }; bool moreWork = await shim.ScheduleDurableTaskEvents(result); Assert.NotNull(request); Assert.Equal(HttpMethod.Get, request.Method); Assert.Equal(new Uri("https://example.com"), request.Uri); Assert.Null(request.Content); Assert.NotNull(request.TokenSource); ManagedIdentityTokenSource tokenSource = Assert.IsType <ManagedIdentityTokenSource>(request.TokenSource); Assert.Equal("https://management.core.windows.net/.default", tokenSource.Resource); Assert.Equal("https://login.microsoftonline.com/", tokenSource.Options.AuthorityHost.ToString()); Assert.Equal("example_tenant_id", tokenSource.Options.TenantId); }
// Handles replaying the Durable Task APIs that the out-of-proc function scheduled // with user code. public async Task HandleDurableTaskReplay(OrchestrationInvocationResult executionJson) { bool moreWorkToDo = await this.ScheduleDurableTaskEvents(executionJson); if (moreWorkToDo) { // We must delay indefinitely to prevent the orchestration instance from completing. // This is effectively what the Durable Task Framework dispatcher does for normal // orchestration execution. await Task.Delay(Timeout.Infinite); } }
internal async Task <bool> ScheduleDurableTaskEvents(OrchestrationInvocationResult result) { var jObj = result.ReturnValue as JObject; if (jObj == null && result.ReturnValue is string jsonText) { try { jObj = JObject.Parse(jsonText); } catch { throw new ArgumentException("Out of proc orchestrators must return a valid JSON schema"); } } if (jObj == null) { throw new ArgumentException("The data returned by the out-of-process function execution was not valid json."); } var execution = JsonConvert.DeserializeObject <OutOfProcOrchestratorState>(jObj.ToString()); if (execution.CustomStatus != null) { this.context.SetCustomStatus(execution.CustomStatus); } await this.ProcessAsyncActions(execution.Actions); if (!string.IsNullOrEmpty(execution.Error)) { string exceptionDetails = $"Message: {execution.Error}, StackTrace: {result.Exception.StackTrace}"; throw new OrchestrationFailureException( $"Orchestrator function '{this.context.Name}' failed: {execution.Error}", exceptionDetails); } if (execution.IsDone) { this.context.SetOutput(execution.Output); return(false); } // there are more executions to process return(true); }
public async Task CallHttpActionOrchestration() { DurableHttpRequest request = null; // Mock the CallHttpAsync API so we can capture the request and return a fixed response. var contextMock = new Mock <IDurableOrchestrationContext>(); contextMock .Setup(ctx => ctx.CallHttpAsync(It.IsAny <DurableHttpRequest>())) .Callback <DurableHttpRequest>(req => request = req) .Returns(Task.FromResult(new DurableHttpResponse(System.Net.HttpStatusCode.OK))); var shim = new OutOfProcOrchestrationShim(contextMock.Object); var executionJson = @" { ""isDone"": false, ""actions"": [ [{ ""actionType"": ""CallHttp"", ""httpRequest"": { ""method"": ""POST"", ""uri"": ""https://example.com"", ""headers"": { ""Content-Type"": ""application/json"", ""Accept"": [""application/json"",""application/xml""], ""x-ms-foo"": [] }, ""content"": ""5"" } }] ] }"; // Feed the out-of-proc execution result JSON to the out-of-proc shim. var jsonObject = JObject.Parse(executionJson); OrchestrationInvocationResult result = new OrchestrationInvocationResult() { ReturnValue = jsonObject, }; bool moreWork = await shim.ScheduleDurableTaskEvents(result); // The request should not have completed because one additional replay is needed // to handle the result of CallHttpAsync. However, this test doesn't care about // completing the orchestration - we just need to validate the CallHttpAsync call. Assert.True(moreWork); Assert.NotNull(request); Assert.Equal(HttpMethod.Post, request.Method); Assert.Equal(new Uri("https://example.com"), request.Uri); Assert.Equal("5", request.Content); Assert.Equal(3, request.Headers.Count); Assert.True(request.Headers.TryGetValue("Content-Type", out StringValues contentTypeValues)); Assert.Single(contentTypeValues); Assert.Equal("application/json", contentTypeValues[0]); Assert.True(request.Headers.TryGetValue("Accept", out StringValues acceptValues)); Assert.Equal(2, acceptValues.Count); Assert.Equal("application/json", acceptValues[0]); Assert.Equal("application/xml", acceptValues[1]); Assert.True(request.Headers.TryGetValue("x-ms-foo", out StringValues customHeaderValues)); Assert.Empty(customHeaderValues); }
private async Task TraceAndReplay(object result, Exception ex = null) { var invocationResult = new OrchestrationInvocationResult(result, ex); await this.outOfProcShim.HandleDurableTaskReplay(invocationResult); }