Skip to content

Commit 4064726

Browse files
authored
Merge branch 'dev' into pthummar/add_py311_tests
2 parents e16daa9 + 0d9b9b2 commit 4064726

File tree

19 files changed

+349
-46
lines changed

19 files changed

+349
-46
lines changed

azure-pipelines.yml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ trigger:
77

88
variables:
99
patchBuildNumberForDev: $(Build.BuildNumber)
10-
PROD_V4_WORKER_PY : 'python/prodV4/worker.py'
10+
PROD_V4_WORKER_PY: 'python/prodV4/worker.py'
1111

1212
jobs:
1313
- job: Build_WINDOWS_X64
@@ -98,7 +98,7 @@ jobs:
9898
artifactName: '$(pythonVersion)_LINUX_X64'
9999
- job: Build_OSX_X64
100100
pool:
101-
vmImage: 'macOS-12'
101+
vmImage: 'macOS-latest'
102102
strategy:
103103
matrix:
104104
Python37V4:
@@ -122,10 +122,30 @@ jobs:
122122
pythonVersion: '$(pythonVersion)'
123123
workerPath: '$(workerPath)'
124124
artifactName: '$(pythonVersion)_OSX_X64'
125+
- job: Build_OSX_ARM64
126+
pool:
127+
vmImage: 'macOS-latest'
128+
strategy:
129+
matrix:
130+
Python39V4:
131+
pythonVersion: '3.9'
132+
workerPath: $(PROD_V4_WORKER_PY)
133+
Python310V4:
134+
pythonVersion: '3.10'
135+
workerPath: $(PROD_V4_WORKER_PY)
136+
Python311V4:
137+
pythonVersion: '3.11'
138+
workerPath: $(PROD_V4_WORKER_PY)
139+
steps:
140+
- template: pack/templates/macos_64_env_gen.yml
141+
parameters:
142+
pythonVersion: '$(pythonVersion)'
143+
workerPath: '$(workerPath)'
144+
artifactName: '$(pythonVersion)_OSX_ARM64'
125145

126146
- job: PackageWorkers
127-
dependsOn: ['Build_WINDOWS_X64', 'Build_WINDOWS_X86', 'Build_LINUX_X64', 'Build_OSX_X64']
128-
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), eq(variables['Build.SourceBranch'], 'refs/heads/dev'))
147+
dependsOn: ['Build_WINDOWS_X64', 'Build_WINDOWS_X86', 'Build_LINUX_X64', 'Build_OSX_X64', 'Build_OSX_ARM64']
148+
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), eq(variables['Build.SourceBranch'], 'refs/heads/dev'), eq(variables['GeneratePackage'], True))
129149
pool:
130150
name: '1ES-Hosted-AzFunc'
131151
demands:
Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,28 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33

4+
from dataclasses import dataclass
5+
from enum import Enum
6+
47
from . import rpcexception
58

69

10+
class RetryPolicy(Enum):
11+
"""Retry policy for the function invocation"""
12+
13+
MAX_RETRY_COUNT = "max_retry_count"
14+
STRATEGY = "strategy"
15+
DELAY_INTERVAL = "delay_interval"
16+
MINIMUM_INTERVAL = "minimum_interval"
17+
MAXIMUM_INTERVAL = "maximum_interval"
18+
19+
20+
@dataclass
721
class RetryContext:
8-
"""Check https://docs.microsoft.com/en-us/azure/azure-functions/
9-
functions-bindings-error-pages?tabs=python#retry-policies-preview"""
10-
11-
def __init__(self,
12-
retry_count: int,
13-
max_retry_count: int,
14-
rpc_exception: rpcexception.RpcException) -> None:
15-
self.__retry_count = retry_count
16-
self.__max_retry_count = max_retry_count
17-
self.__rpc_exception = rpc_exception
18-
19-
@property
20-
def retry_count(self) -> int:
21-
"""Gets the current retry count from retry-context"""
22-
return self.__retry_count
23-
24-
@property
25-
def max_retry_count(self) -> int:
26-
"""Gets the max retry count from retry-context"""
27-
return self.__max_retry_count
28-
29-
@property
30-
def exception(self) -> rpcexception.RpcException:
31-
return self.__rpc_exception
22+
"""Gets the current retry count from retry-context"""
23+
retry_count: int
24+
25+
"""Gets the max retry count from retry-context"""
26+
max_retry_count: int
27+
28+
rpc_exception: rpcexception.RpcException

azure_functions_worker/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,6 @@
5151
SCRIPT_FILE_NAME = "function_app.py"
5252

5353
PYTHON_LANGUAGE_RUNTIME = "python"
54+
55+
# Settings for V2 programming model
56+
RETRY_POLICY = "retry_policy"

azure_functions_worker/dispatcher.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,10 @@ def index_functions(self, function_path: str):
609609
len(indexed_functions))
610610

611611
if indexed_functions:
612+
fx_metadata_results = loader.process_indexed_function(
613+
self._functions,
614+
indexed_functions)
615+
612616
indexed_function_logs: List[str] = []
613617
for func in indexed_functions:
614618
function_log = "Function Name: {}, Function Binding: {}" \
@@ -621,10 +625,6 @@ def index_functions(self, function_path: str):
621625
'Successfully processed FunctionMetadataRequest for '
622626
'functions: %s', " ".join(indexed_function_logs))
623627

624-
fx_metadata_results = loader.process_indexed_function(
625-
self._functions,
626-
indexed_functions)
627-
628628
return fx_metadata_results
629629

630630
async def _handle__close_shared_memory_resources_request(self, request):

azure_functions_worker/loader.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88
import os.path
99
import pathlib
1010
import sys
11+
import time
12+
from datetime import timedelta
1113
from os import PathLike, fspath
1214
from typing import Optional, Dict
1315

16+
from google.protobuf.duration_pb2 import Duration
17+
1418
from . import protos, functions
19+
from .bindings.retrycontext import RetryPolicy
1520
from .constants import MODULE_NOT_FOUND_TS_URL, SCRIPT_FILE_NAME, \
16-
PYTHON_LANGUAGE_RUNTIME
21+
PYTHON_LANGUAGE_RUNTIME, RETRY_POLICY
1722
from .utils.wrappers import attach_message_to_exception
1823

1924
_AZURE_NAMESPACE = '__app__'
@@ -45,6 +50,12 @@ def install() -> None:
4550
sys.modules[_AZURE_NAMESPACE] = ns_pkg
4651

4752

53+
def convert_to_seconds(timestr: str):
54+
x = time.strptime(timestr, '%H:%M:%S')
55+
return int(timedelta(hours=x.tm_hour, minutes=x.tm_min,
56+
seconds=x.tm_sec).total_seconds())
57+
58+
4859
def uninstall() -> None:
4960
pass
5061

@@ -60,6 +71,39 @@ def build_binding_protos(indexed_function) -> Dict:
6071
return binding_protos
6172

6273

74+
def build_retry_protos(indexed_function) -> Dict:
75+
retry = indexed_function.get_settings_dict(RETRY_POLICY)
76+
if not retry:
77+
return None
78+
79+
strategy = retry.get(RetryPolicy.STRATEGY.value)
80+
if strategy == "fixed_delay":
81+
delay_interval = Duration(
82+
seconds=convert_to_seconds(
83+
retry.get(RetryPolicy.DELAY_INTERVAL.value)))
84+
retry_protos = protos.RpcRetryOptions(
85+
max_retry_count=int(retry.get(RetryPolicy.MAX_RETRY_COUNT.value)),
86+
retry_strategy=retry.get(RetryPolicy.STRATEGY.value),
87+
delay_interval=delay_interval,
88+
)
89+
else:
90+
minimum_interval = Duration(
91+
seconds=convert_to_seconds(
92+
retry.get(RetryPolicy.MINIMUM_INTERVAL.value)))
93+
maximum_interval = Duration(
94+
seconds=convert_to_seconds(
95+
retry.get(RetryPolicy.MAXIMUM_INTERVAL.value)))
96+
97+
retry_protos = protos.RpcRetryOptions(
98+
max_retry_count=int(retry.get(RetryPolicy.MAX_RETRY_COUNT.value)),
99+
retry_strategy=retry.get(RetryPolicy.STRATEGY.value),
100+
minimum_interval=minimum_interval,
101+
maximum_interval=maximum_interval
102+
)
103+
104+
return retry_protos
105+
106+
63107
def process_indexed_function(functions_registry: functions.Registry,
64108
indexed_functions):
65109
fx_metadata_results = []
@@ -68,6 +112,7 @@ def process_indexed_function(functions_registry: functions.Registry,
68112
function=indexed_function)
69113

70114
binding_protos = build_binding_protos(indexed_function)
115+
retry_protos = build_retry_protos(indexed_function)
71116

72117
function_metadata = protos.RpcFunctionMetadata(
73118
name=function_info.name,
@@ -80,6 +125,7 @@ def process_indexed_function(functions_registry: functions.Registry,
80125
language=PYTHON_LANGUAGE_RUNTIME,
81126
bindings=binding_protos,
82127
raw_bindings=indexed_function.get_raw_bindings(),
128+
retry_options=retry_protos,
83129
properties={"worker_indexed": "True"})
84130

85131
fx_metadata_results.append(function_metadata)

azure_functions_worker/protos/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
CloseSharedMemoryResourcesResponse,
3333
FunctionsMetadataRequest,
3434
FunctionMetadataResponse,
35-
WorkerMetadata)
35+
WorkerMetadata,
36+
RpcRetryOptions)
3637

3738
from .shared.NullableTypes_pb2 import (
3839
NullableString,

azure_functions_worker/protos/_src/src/proto/FunctionRpc.proto

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ message StreamingMessage {
8686

8787
// Host gets the list of function load responses
8888
FunctionLoadResponseCollection function_load_response_collection = 32;
89+
90+
// Host sends required metadata to worker to warmup the worker
91+
WorkerWarmupRequest worker_warmup_request = 33;
92+
93+
// Worker responds after warming up with the warmup result
94+
WorkerWarmupResponse worker_warmup_response = 34;
95+
8996
}
9097
}
9198

@@ -330,6 +337,9 @@ message RpcFunctionMetadata {
330337
// A flag indicating if managed dependency is enabled or not
331338
bool managed_dependency_enabled = 14;
332339

340+
// The optional function execution retry strategy to use on invocation failures.
341+
RpcRetryOptions retry_options = 15;
342+
333343
// Properties for function metadata
334344
// They're usually specific to a worker and largely passed along to the controller API for use
335345
// outside the host
@@ -423,6 +433,15 @@ message InvocationResponse {
423433
StatusResult result = 3;
424434
}
425435

436+
message WorkerWarmupRequest {
437+
// Full path of worker.config.json location
438+
string worker_directory = 1;
439+
}
440+
441+
message WorkerWarmupResponse {
442+
StatusResult result = 1;
443+
}
444+
426445
// Used to encapsulate data which could be a variety of types
427446
message TypedData {
428447
oneof data {
@@ -681,4 +700,31 @@ message ModelBindingData
681700
// Used to encapsulate collection model_binding_data
682701
message CollectionModelBindingData {
683702
repeated ModelBindingData model_binding_data = 1;
703+
}
704+
705+
// Retry policy which the worker sends the host when the worker indexes
706+
// a function.
707+
message RpcRetryOptions
708+
{
709+
// The retry strategy to use. Valid values are fixed delay or exponential backoff.
710+
enum RetryStrategy
711+
{
712+
exponential_backoff = 0;
713+
fixed_delay = 1;
714+
}
715+
716+
// The maximum number of retries allowed per function execution.
717+
// -1 means to retry indefinitely.
718+
int32 max_retry_count = 2;
719+
720+
// The delay that's used between retries when you're using a fixed delay strategy.
721+
google.protobuf.Duration delay_interval = 3;
722+
723+
// The minimum retry delay when you're using an exponential backoff strategy
724+
google.protobuf.Duration minimum_interval = 4;
725+
726+
// The maximum retry delay when you're using an exponential backoff strategy
727+
google.protobuf.Duration maximum_interval = 5;
728+
729+
RetryStrategy retry_strategy = 6;
684730
}

azure_functions_worker/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33

4-
VERSION = '4.14.0'
4+
VERSION = '4.15.0'

pack/Microsoft.Azure.Functions.V4.PythonWorker.nuspec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@
2222
<file src="..\3.9_WINDOWS_X86\**" target="tools\3.9\WINDOWS\X86" />
2323
<file src="..\3.9_LINUX_X64\**" target="tools\3.9\LINUX\X64" />
2424
<file src="..\3.9_OSX_X64\**" target="tools\3.9\OSX\X64" />
25+
<file src="..\3.9_OSX_X64\**" target="tools\3.9\OSX\Arm64" />
2526
<file src="..\3.10_WINDOWS_X64\**" target="tools\3.10\WINDOWS\X64" />
2627
<file src="..\3.10_WINDOWS_X86\**" target="tools\3.10\WINDOWS\X86" />
2728
<file src="..\3.10_LINUX_X64\**" target="tools\3.10\LINUX\X64" />
2829
<file src="..\3.10_OSX_X64\**" target="tools\3.10\OSX\X64" />
30+
<file src="..\3.10_OSX_X64\**" target="tools\3.10\OSX\Arm64" />
2931
<file src="..\3.11_WINDOWS_X64\**" target="tools\3.11\WINDOWS\X64" />
3032
<file src="..\3.11_WINDOWS_X86\**" target="tools\3.11\WINDOWS\X86" />
3133
<file src="..\3.11_LINUX_X64\**" target="tools\3.11\LINUX\X64" />
3234
<file src="..\3.11_OSX_X64\**" target="tools\3.11\OSX\X64" />
35+
<file src="..\3.11_OSX_X64\**" target="tools\3.11\OSX\Arm64" />
3336
<file src="..\python\prodV4\worker.config.json" target="tools" />
3437
<file src="Microsoft.Azure.Functions.PythonWorker.targets" target="build" />
3538
<file src="..\_manifest\manifest.json" target="SBOM\manifest.json" />

pack/scripts/mac_arm64_deps.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
3+
python -m venv .env
4+
source .env/bin/activate
5+
python -m pip install --upgrade pip==23.0
6+
7+
python -m pip install .
8+
9+
python -m pip install . --no-compile --target "$BUILD_SOURCESDIRECTORY/deps"

pack/templates/macos_64_env_gen.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
parameters:
2+
pythonVersion: ''
3+
artifactName: ''
4+
workerPath: ''
5+
6+
steps:
7+
- task: UsePythonVersion@0
8+
inputs:
9+
versionSpec: ${{ parameters.pythonVersion }}
10+
addToPath: true
11+
- task: ShellScript@2
12+
inputs:
13+
disableAutoCwd: true
14+
scriptPath: 'pack/scripts/mac_arm64_deps.sh'
15+
- task: CopyFiles@2
16+
inputs:
17+
contents: |
18+
${{ parameters.workerPath }}
19+
targetFolder: '$(Build.ArtifactStagingDirectory)'
20+
flattenFolders: true
21+
- task: CopyFiles@2
22+
inputs:
23+
sourceFolder: '$(Build.SourcesDirectory)/deps'
24+
contents: |
25+
**
26+
!grpc_tools/**/*
27+
!grpcio_tools*/*
28+
targetFolder: '$(Build.ArtifactStagingDirectory)'
29+
- task: PublishBuildArtifacts@1
30+
inputs:
31+
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
32+
artifactName: ${{ parameters.artifactName }}

python/prodV4/worker.config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"description":{
33
"language":"python",
4-
"defaultRuntimeVersion":"3.9",
4+
"defaultRuntimeVersion":"3.10",
55
"supportedOperatingSystems":["LINUX", "OSX", "WINDOWS"],
66
"supportedRuntimeVersions":["3.7", "3.8", "3.9", "3.10", "3.11"],
7-
"supportedArchitectures":["X64", "X86"],
7+
"supportedArchitectures":["X64", "X86", "Arm64"],
88
"extensions":[".py"],
99
"defaultExecutablePath":"python",
1010
"defaultWorkerPath":"%FUNCTIONS_WORKER_RUNTIME_VERSION%/{os}/{architecture}/worker.py",

0 commit comments

Comments
 (0)