Skip to content

Commit 6497fd9

Browse files
Added RetryContext (#712) (#713)
* Updated subtree from https://github.com/azure/azure-functions-language-worker-protobuf. Tag: v1.5.1-protobuf. Commit: 2fc14be59bbd8bb9f3f6275247047675b83fb3ca * Add RetryContext * Added tests * Added unit tests and removed E2E tests * Fix RetryContext unit test * Updated release_notes.md * Addressing requested changes
1 parent 67f933a commit 6497fd9

File tree

12 files changed

+218
-33
lines changed

12 files changed

+218
-33
lines changed

protobuf/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ mkdir %MSGDIR%
6161
6262
set OUTDIR=%MSGDIR%\DotNet
6363
mkdir %OUTDIR%
64-
%GRPC_TOOLS_PATH%\protoc.exe %PROTO% --csharp_out %OUTDIR% --grpc_out=%OUTDIR% --plugin=protoc-gen-grpc=%GRPC_TOOLS_PATH%\grpc_csharp_plugin.exe --proto_path=%PROTO_PATH% --proto_path=%PROTOBUF_TOOLS%
64+
%GRPC_TOOLS_PATH%\protoc.exe %PROTO% --csharp_out %OUTDIR% --grpc_out=%OUTDIR% --plugin=protoc-gen-grpc=%GRPC_TOOLS_PATH%\grpc_csharp_plugin.exe --proto_path=%PROTO_PATH% --proto_path=%PROTOBUF_TOOLS%
6565
```
6666
## JavaScript
6767
In package.json, add to the build script the following commands to build .js files and to build .ts files. Use and install npm package `protobufjs`.
@@ -81,7 +81,10 @@ In pom.xml add following under configuration for this plugin
8181
<protoSourceRoot>${basedir}/<path to this repo>/azure-functions-language-worker-protobuf/src/proto</protoSourceRoot>
8282

8383
## Python
84-
--TODO
84+
```
85+
python -m pip install -e .[dev] -U
86+
python setup.py build
87+
```
8588

8689
## Contributing
8790

protobuf/src/proto/FunctionRpc.proto

Lines changed: 105 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,18 @@ message StreamingMessage {
6767

6868
// Worker logs a message back to the host
6969
RpcLog rpc_log = 2;
70-
70+
7171
FunctionEnvironmentReloadRequest function_environment_reload_request = 25;
7272

7373
FunctionEnvironmentReloadResponse function_environment_reload_response = 26;
74+
75+
// Ask the worker to close any open shared memory resources for a given invocation
76+
CloseSharedMemoryResourcesRequest close_shared_memory_resources_request = 27;
77+
CloseSharedMemoryResourcesResponse close_shared_memory_resources_response = 28;
78+
79+
// Worker indexing message types
80+
FunctionsMetadataRequest functions_metadata_request = 29;
81+
FunctionMetadataResponses function_metadata_responses = 30;
7482
}
7583
}
7684

@@ -201,6 +209,17 @@ message FunctionEnvironmentReloadResponse {
201209
StatusResult result = 3;
202210
}
203211

212+
// Tell the out-of-proc worker to close any shared memory maps it allocated for given invocation
213+
message CloseSharedMemoryResourcesRequest {
214+
repeated string map_names = 1;
215+
}
216+
217+
// Response from the worker indicating which of the shared memory maps have been successfully closed and which have not been closed
218+
// The key (string) is the map name and the value (bool) is true if it was closed, false if not
219+
message CloseSharedMemoryResourcesResponse {
220+
map<string, bool> close_map_results = 1;
221+
}
222+
204223
// Host tells the worker to load a Function
205224
message FunctionLoadRequest {
206225
// unique function identifier (avoid name collisions, facilitate reload case)
@@ -245,6 +264,30 @@ message RpcFunctionMetadata {
245264

246265
// Is set to true for proxy
247266
bool is_proxy = 7;
267+
268+
// Function indexing status
269+
StatusResult status = 8;
270+
271+
// Function language
272+
string language = 9;
273+
274+
// Raw binding info
275+
repeated string raw_bindings = 10;
276+
}
277+
278+
// Host tells worker it is ready to receive metadata
279+
message FunctionsMetadataRequest {
280+
// base directory for function app
281+
string function_app_directory = 1;
282+
}
283+
284+
// Worker sends function metadata back to host
285+
message FunctionMetadataResponses {
286+
// list of function indexing responses
287+
repeated FunctionLoadRequest function_load_requests_results = 1;
288+
289+
// status of overall metadata request
290+
StatusResult result = 2;
248291
}
249292

250293
// Host requests worker to invoke a Function
@@ -263,6 +306,9 @@ message InvocationRequest {
263306

264307
// Populates activityId, tracestate and tags from host
265308
RpcTraceContext trace_context = 5;
309+
310+
// Current retry context
311+
RetryContext retry_context = 6;
266312
}
267313

268314
// Host sends ActivityId, traceStateString and Tags from host
@@ -277,6 +323,18 @@ message RpcTraceContext {
277323
map<string, string> attributes = 3;
278324
}
279325

326+
// Host sends retry context for a function invocation
327+
message RetryContext {
328+
// Current retry count
329+
int32 retry_count = 1;
330+
331+
// Max retry count
332+
int32 max_retry_count = 2;
333+
334+
// Exception that caused the retry
335+
RpcException exception = 3;
336+
}
337+
280338
// Host requests worker to cancel invocation
281339
message InvocationCancel {
282340
// Unique id for invocation
@@ -318,6 +376,34 @@ message TypedData {
318376
}
319377
}
320378

379+
// Specify which type of data is contained in the shared memory region being read
380+
enum RpcDataType {
381+
unknown = 0;
382+
string = 1;
383+
json = 2;
384+
bytes = 3;
385+
stream = 4;
386+
http = 5;
387+
int = 6;
388+
double = 7;
389+
collection_bytes = 8;
390+
collection_string = 9;
391+
collection_double = 10;
392+
collection_sint64 = 11;
393+
}
394+
395+
// Used to provide metadata about shared memory region to read data from
396+
message RpcSharedMemory {
397+
// Name of the shared memory map containing data
398+
string name = 1;
399+
// Offset in the shared memory map to start reading data from
400+
int64 offset = 2;
401+
// Number of bytes to read (starting from the offset)
402+
int64 count = 3;
403+
// Final type to which the read data (in bytes) is to be interpreted as
404+
RpcDataType type = 4;
405+
}
406+
321407
// Used to encapsulate collection string
322408
message CollectionString {
323409
repeated string string = 1;
@@ -343,8 +429,13 @@ message ParameterBinding {
343429
// Name for the binding
344430
string name = 1;
345431

346-
// Data for the binding
347-
TypedData data = 2;
432+
oneof rpc_data {
433+
// Data for the binding
434+
TypedData data = 2;
435+
436+
// Metadata about the shared memory region to read data from
437+
RpcSharedMemory rpc_shared_memory = 3;
438+
}
348439
}
349440

350441
// Used to describe a given binding on load
@@ -390,8 +481,9 @@ message RpcLog {
390481

391482
// Category of the log. Defaults to User if not specified.
392483
enum RpcLogCategory {
393-
User = 0;
394-
System = 1;
484+
User = 0;
485+
System = 1;
486+
CustomMetric = 2;
395487
}
396488

397489
// Unique id for invocation (if exists)
@@ -413,11 +505,14 @@ message RpcLog {
413505
// Exception (if exists)
414506
RpcException exception = 6;
415507

416-
// json serialized property bag, or could use a type scheme like map<string, TypedData>
508+
// json serialized property bag
417509
string properties = 7;
418510

419-
// Category of the log. Either user(default) or system.
511+
// Category of the log. Either user(default), system, or custom metric.
420512
RpcLogCategory log_category = 8;
513+
514+
// strongly-typed (ish) property bag
515+
map<string, TypedData> propertiesMap = 9;
421516
}
422517

423518
// Encapsulates an Exception
@@ -484,4 +579,7 @@ message RpcHttp {
484579
TypedData rawBody = 17;
485580
repeated RpcClaimsIdentity identities = 18;
486581
repeated RpcHttpCookie cookies = 19;
582+
map<string,NullableString> nullable_headers = 20;
583+
map<string,NullableString> nullable_params = 21;
584+
map<string,NullableString> nullable_query = 22;
487585
}

src/FunctionInfo.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ internal class AzFunctionInfo
2424
{
2525
internal const string TriggerMetadata = "TriggerMetadata";
2626
internal const string TraceContext = "TraceContext";
27+
internal const string RetryContext = "RetryContext";
2728
internal const string DollarReturn = "$return";
2829

2930
internal readonly bool HasTriggerMetadataParam;
3031
internal readonly bool HasTraceContextParam;
32+
internal readonly bool HasRetryContextParam;
3133

3234
internal readonly string FuncDirectory;
3335
internal readonly string FuncName;
@@ -76,6 +78,7 @@ internal AzFunctionInfo(RpcFunctionMetadata metadata)
7678
var parametersCopy = new Dictionary<string, PSScriptParamInfo>(psScriptParams, StringComparer.OrdinalIgnoreCase);
7779
HasTriggerMetadataParam = parametersCopy.Remove(TriggerMetadata);
7880
HasTraceContextParam = parametersCopy.Remove(TraceContext);
81+
HasRetryContextParam = parametersCopy.Remove(RetryContext);
7982

8083
var allBindings = new Dictionary<string, ReadOnlyBindingInfo>(StringComparer.OrdinalIgnoreCase);
8184
var inputBindings = new Dictionary<string, ReadOnlyBindingInfo>(StringComparer.OrdinalIgnoreCase);

src/PowerShell/PowerShellManager.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ public Hashtable InvokeFunction(
199199
AzFunctionInfo functionInfo,
200200
Hashtable triggerMetadata,
201201
TraceContext traceContext,
202+
RetryContext retryContext,
202203
IList<ParameterBinding> inputData,
203204
FunctionInvocationPerformanceStopwatch stopwatch)
204205
{
@@ -213,7 +214,7 @@ public Hashtable InvokeFunction(
213214
AddEntryPointInvocationCommand(functionInfo);
214215
stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.FunctionCodeReady);
215216

216-
SetInputBindingParameterValues(functionInfo, inputData, durableController, triggerMetadata, traceContext);
217+
SetInputBindingParameterValues(functionInfo, inputData, durableController, triggerMetadata, traceContext, retryContext);
217218
stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.InputBindingValuesReady);
218219

219220
if (!durableController.ShouldSuppressPipelineTraces())
@@ -258,7 +259,8 @@ private void SetInputBindingParameterValues(
258259
IEnumerable<ParameterBinding> inputData,
259260
DurableController durableController,
260261
Hashtable triggerMetadata,
261-
TraceContext traceContext)
262+
TraceContext traceContext,
263+
RetryContext retryContext)
262264
{
263265
foreach (var binding in inputData)
264266
{
@@ -284,6 +286,11 @@ private void SetInputBindingParameterValues(
284286
{
285287
_pwsh.AddParameter(AzFunctionInfo.TraceContext, traceContext);
286288
}
289+
290+
if (functionInfo.HasRetryContextParam)
291+
{
292+
_pwsh.AddParameter(AzFunctionInfo.RetryContext, retryContext);
293+
}
287294
}
288295

289296
/// <summary>

src/Public/RetryContext.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
7+
8+
namespace Microsoft.Azure.Functions.PowerShellWorker
9+
{
10+
/// <summary>
11+
/// Custom RetryContext constructed from the RpcRetryContext member received from the host.
12+
/// </summary>
13+
internal class RetryContext
14+
{
15+
public RetryContext(int retryCount, int maxRetryCount, RpcException exception)
16+
{
17+
RetryCount = retryCount;
18+
MaxRetryCount = maxRetryCount;
19+
Exception = exception;
20+
}
21+
22+
public int RetryCount { get; }
23+
24+
public int MaxRetryCount { get; }
25+
26+
public RpcException Exception { get; }
27+
}
28+
}

src/RequestProcessor.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,9 +329,10 @@ private Hashtable InvokeFunction(
329329
{
330330
var triggerMetadata = GetTriggerMetadata(functionInfo, invocationRequest);
331331
var traceContext = GetTraceContext(functionInfo, invocationRequest);
332+
var retryContext = GetRetryContext(functionInfo, invocationRequest);
332333
stopwatch.OnCheckpoint(FunctionInvocationPerformanceStopwatch.Checkpoint.MetadataAndTraceContextReady);
333334

334-
return psManager.InvokeFunction(functionInfo, triggerMetadata, traceContext, invocationRequest.InputData, stopwatch);
335+
return psManager.InvokeFunction(functionInfo, triggerMetadata, traceContext, retryContext, invocationRequest.InputData, stopwatch);
335336
}
336337

337338
internal StreamingMessage ProcessInvocationCancelRequest(StreamingMessage request)
@@ -452,6 +453,19 @@ private static TraceContext GetTraceContext(AzFunctionInfo functionInfo, Invocat
452453
invocationRequest.TraceContext.Attributes);
453454
}
454455

456+
private static RetryContext GetRetryContext(AzFunctionInfo functionInfo, InvocationRequest invocationRequest)
457+
{
458+
if (!functionInfo.HasRetryContextParam)
459+
{
460+
return null;
461+
}
462+
463+
return new RetryContext(
464+
invocationRequest.RetryContext.RetryCount,
465+
invocationRequest.RetryContext.MaxRetryCount,
466+
invocationRequest.RetryContext.Exception);
467+
}
468+
455469
/// <summary>
456470
/// Set the 'ReturnValue' and 'OutputData' based on the invocation results appropriately.
457471
/// </summary>

src/Utility/TypeExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ internal static RpcException ToRpcException(this Exception exception)
153153
{
154154
return new RpcException
155155
{
156-
Message = exception.Message,
157156
Source = exception.Source ?? "",
158-
StackTrace = exception.StackTrace ?? ""
157+
StackTrace = exception.StackTrace ?? "",
158+
Message = exception.Message
159159
};
160160
}
161161

test/Unit/Function/FunctionLoaderTests.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,12 @@ public void TestFunctionLoaderGetFuncWithRequires()
100100
Assert.Single(funcInfo.OutputBindings);
101101
}
102102

103-
[Fact]
104-
public void TestFunctionLoaderGetFuncWithTriggerMetadataParam()
103+
[Theory]
104+
[InlineData("TriggerMetadata")]
105+
[InlineData("RetryContext")]
106+
public void TestFunctionLoaderGetFuncWithSingleParam(string paramName)
105107
{
106-
var scriptFileToUse = Path.Join(_functionDirectory, "BasicFuncScriptWithTriggerMetadata.ps1");
108+
var scriptFileToUse = Path.Join(_functionDirectory, $"BasicFuncScriptWith{paramName}.ps1");
107109
var entryPointToUse = string.Empty;
108110
var functionLoadRequest = GetFuncLoadRequest(scriptFileToUse, entryPointToUse);
109111

@@ -118,7 +120,7 @@ public void TestFunctionLoaderGetFuncWithTriggerMetadataParam()
118120
Assert.Equal(3, funcInfo.FuncParameters.Count);
119121
Assert.True(funcInfo.FuncParameters.ContainsKey("req"));
120122
Assert.True(funcInfo.FuncParameters.ContainsKey("inputBlob"));
121-
Assert.True(funcInfo.FuncParameters.ContainsKey("TriggerMetadata"));
123+
Assert.True(funcInfo.FuncParameters.ContainsKey(paramName));
122124

123125
Assert.Equal(3, funcInfo.AllBindings.Count);
124126
Assert.Equal(2, funcInfo.InputBindings.Count);
@@ -229,10 +231,12 @@ public void ParametersShouldMatchInputBinding()
229231
Assert.Contains("inputBlob", exception.Message);
230232
}
231233

232-
[Fact]
233-
public void ParametersShouldMatchInputBindingWithTriggerMetadataParam()
234+
[Theory]
235+
[InlineData("TriggerMetadata")]
236+
[InlineData("RetryContext")]
237+
public void ParametersShouldMatchInputBindingWithSingleParam(string paramName)
234238
{
235-
var scriptFileToUse = Path.Join(_functionDirectory, "BasicFuncScriptWithTriggerMetadata.ps1");
239+
var scriptFileToUse = Path.Join(_functionDirectory, $"BasicFuncScriptWith{paramName}.ps1");
236240
var entryPointToUse = string.Empty;
237241

238242
var functionLoadRequest = GetFuncLoadRequest(scriptFileToUse, entryPointToUse);
@@ -262,9 +266,9 @@ public void EntryPointParametersShouldMatchInputBinding()
262266
}
263267

264268
[Fact]
265-
public void EntryPointParametersShouldMatchInputBindingWithTriggerMetadataParam()
269+
public void EntryPointParametersShouldMatchInputBindingWithTriggerMetadataAndRetryContextParams()
266270
{
267-
var scriptFileToUse = Path.Join(_functionDirectory, "FuncWithEntryPointAndTriggerMetadata.psm1");
271+
var scriptFileToUse = Path.Join(_functionDirectory, "FuncWithEntryPointAndTriggerMetadataAndRetryContext.psm1");
268272
var entryPointToUse = "Run";
269273

270274
var functionLoadRequest = GetFuncLoadRequest(scriptFileToUse, entryPointToUse);

0 commit comments

Comments
 (0)