-
Notifications
You must be signed in to change notification settings - Fork 268
/
FunctionExecutionHelper.cs
139 lines (126 loc) · 5.7 KB
/
FunctionExecutionHelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#nullable enable
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Host.Executors;
namespace Microsoft.Azure.WebJobs.Extensions.DurableTask.Listener
{
internal static class FunctionExecutionHelper
{
public static async Task<WrappedFunctionResult> ExecuteFunctionInOrchestrationMiddleware(
ITriggeredFunctionExecutor executor,
TriggeredFunctionData triggerInput,
TaskCommonShim shim,
DurableCommonContext context,
CancellationToken cancellationToken)
{
#pragma warning disable CS0618 // InvokeHandler approved for use by this extension
if (triggerInput.InvokeHandler == null)
{
throw new ArgumentException(
$"{nameof(ExecuteFunctionInOrchestrationMiddleware)} should only be used when ${nameof(triggerInput)} has a value for ${nameof(TriggeredFunctionData.InvokeHandler)}");
}
try
{
context.ExecutorCalledBack = false;
FunctionResult result = await executor.TryExecuteAsync(triggerInput, cancellationToken);
if (result.Succeeded)
{
return WrappedFunctionResult.Success();
}
if (cancellationToken.IsCancellationRequested)
{
return WrappedFunctionResult.FunctionHostStoppingFailure(result.Exception);
}
if (context.ExecutorCalledBack)
{
// the problem did happen while the function code was executing.
// So it is either a user code failure or a function timeout.
if (result.Exception is Microsoft.Azure.WebJobs.Host.FunctionTimeoutException)
{
shim.TimeoutTriggered(result.Exception);
return WrappedFunctionResult.FunctionTimeoutFailure(result.Exception);
}
else
{
return WrappedFunctionResult.UserCodeFailure(result.Exception);
}
}
else
{
// The problem happened before the function code even got called.
// This can happen if the constructor for a non-static function fails, for example.
// We want this to appear as if the function code threw the exception.
// So we execute the middleware directly, instead of via the executor.
try
{
var exception = result.Exception ?? new InvalidOperationException("The function failed to start executing.");
await triggerInput.InvokeHandler(() => Task.FromException<object>(exception));
return WrappedFunctionResult.Success();
}
catch (Exception e) when (!cancellationToken.IsCancellationRequested)
{
return WrappedFunctionResult.UserCodeFailure(e);
}
}
#pragma warning restore CS0618
}
catch (Exception e)
{
if (cancellationToken.IsCancellationRequested)
{
return WrappedFunctionResult.FunctionHostStoppingFailure(e);
}
else
{
return WrappedFunctionResult.FunctionRuntimeFailure(e);
}
}
}
public static async Task<WrappedFunctionResult> ExecuteActivityFunction(
ITriggeredFunctionExecutor executor,
TriggeredFunctionData triggerInput,
CancellationToken cancellationToken)
{
#pragma warning disable CS0618 // InvokeHandler approved for use by this extension
if (triggerInput.InvokeHandler != null)
{
// Activity functions cannot use InvokeHandler, because the usage of InvokeHandler prevents the function from
// returning a value in the way that the Activity shim knows how to handle.
throw new ArgumentException(
$"{nameof(ExecuteActivityFunction)} cannot be used when ${nameof(triggerInput)} has a value for ${nameof(TriggeredFunctionData.InvokeHandler)}");
}
#pragma warning restore CS0618
try
{
FunctionResult result = await executor.TryExecuteAsync(triggerInput, cancellationToken);
if (result.Succeeded)
{
return WrappedFunctionResult.Success();
}
if (cancellationToken.IsCancellationRequested)
{
return WrappedFunctionResult.FunctionHostStoppingFailure(result.Exception);
}
if (result.Exception is Microsoft.Azure.WebJobs.Host.FunctionTimeoutException)
{
return WrappedFunctionResult.FunctionTimeoutFailure(result.Exception);
}
return WrappedFunctionResult.UserCodeFailure(result.Exception);
}
catch (Exception e)
{
if (cancellationToken.IsCancellationRequested)
{
return WrappedFunctionResult.FunctionHostStoppingFailure(e);
}
else
{
return WrappedFunctionResult.FunctionRuntimeFailure(e);
}
}
}
}
}