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);
        }
Example #2
0
        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);
        }
Example #3
0
        // 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);
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        private async Task TraceAndReplay(object result, Exception ex = null)
        {
            var invocationResult = new OrchestrationInvocationResult(result, ex);

            await this.outOfProcShim.HandleDurableTaskReplay(invocationResult);
        }