azure-functions-runtime 1.0.0.dev0__tar.gz → 1.1.0b2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/PKG-INFO +3 -2
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/__init__.py +9 -1
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/meta.py +41 -10
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/nullable_converters.py +13 -1
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/functions.py +27 -11
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/handle_event.py +19 -8
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/http_v2.py +2 -2
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/loader.py +22 -4
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/otel.py +1 -1
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/constants.py +1 -0
- azure_functions_runtime-1.1.0b2/azure_functions_runtime/utils/threadpool.py +88 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/tracing.py +22 -24
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/version.py +1 -1
- {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/azure_functions_runtime.egg-info/PKG-INFO +3 -2
- azure_functions_runtime-1.1.0b2/azure_functions_runtime.egg-info/SOURCES.txt +33 -0
- {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/azure_functions_runtime.egg-info/requires.txt +1 -0
- azure_functions_runtime-1.1.0b2/azure_functions_runtime.egg-info/top_level.txt +2 -0
- {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/pyproject.toml +5 -4
- azure_functions_runtime-1.0.0.dev0/azure_functions_runtime.egg-info/SOURCES.txt +0 -32
- azure_functions_runtime-1.0.0.dev0/azure_functions_runtime.egg-info/top_level.txt +0 -3
- {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/README.md +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/context.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/datumdef.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/generic.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/out.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/retrycontext.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/bindings/tracecontext.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/logging.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/__init__.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/app_setting_manager.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/executor.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/helpers.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/typing_inspect.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/validators.py +0 -0
- {azure_functions_runtime-1.0.0.dev0/azure_functions_worker_v2 → azure_functions_runtime-1.1.0b2/azure_functions_runtime}/utils/wrappers.py +0 -0
- {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/azure_functions_runtime.egg-info/dependency_links.txt +0 -0
- {azure_functions_runtime-1.0.0.dev0 → azure_functions_runtime-1.1.0b2}/setup.cfg +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: azure-functions-runtime
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0b2
|
|
4
4
|
Summary: Python Language Worker for Azure Functions Runtime
|
|
5
5
|
Author-email: "Azure Functions team at Microsoft Corp." <azurefunctions@microsoft.com>
|
|
6
|
-
Project-URL: Documentation, https://github.com/Azure/azure-functions-python-worker/blob/dev/
|
|
6
|
+
Project-URL: Documentation, https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_runtime/README.md
|
|
7
7
|
Project-URL: Repository, https://github.com/Azure/azure-functions-python-worker
|
|
8
8
|
Keywords: azure,functions,azurefunctions,python,serverless
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -29,6 +29,7 @@ Requires-Dist: requests==2.*; extra == "dev"
|
|
|
29
29
|
Requires-Dist: coverage; extra == "dev"
|
|
30
30
|
Requires-Dist: grpcio~=1.70.0; extra == "dev"
|
|
31
31
|
Requires-Dist: grpcio-tools~=1.70.0; extra == "dev"
|
|
32
|
+
Requires-Dist: protobuf~=5.29.0; extra == "dev"
|
|
32
33
|
Requires-Dist: pytest-sugar; extra == "dev"
|
|
33
34
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
34
35
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
@@ -5,9 +5,17 @@ from .handle_event import (worker_init_request,
|
|
|
5
5
|
function_environment_reload_request,
|
|
6
6
|
invocation_request,
|
|
7
7
|
function_load_request)
|
|
8
|
+
from .utils.threadpool import (
|
|
9
|
+
start_threadpool_executor,
|
|
10
|
+
stop_threadpool_executor,
|
|
11
|
+
get_threadpool_executor,
|
|
12
|
+
)
|
|
8
13
|
|
|
9
14
|
__all__ = ('worker_init_request',
|
|
10
15
|
'functions_metadata_request',
|
|
11
16
|
'function_environment_reload_request',
|
|
12
17
|
'invocation_request',
|
|
13
|
-
'function_load_request'
|
|
18
|
+
'function_load_request',
|
|
19
|
+
'start_threadpool_executor',
|
|
20
|
+
'stop_threadpool_executor',
|
|
21
|
+
'get_threadpool_executor')
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
2
|
# Licensed under the MIT License.
|
|
3
3
|
# mypy: disable-error-code="attr-defined"
|
|
4
|
-
import importlib.util
|
|
5
4
|
import os
|
|
6
5
|
import sys
|
|
7
6
|
|
|
@@ -16,9 +15,9 @@ from ..utils.constants import (
|
|
|
16
15
|
CUSTOMER_PACKAGES_PATH,
|
|
17
16
|
HTTP,
|
|
18
17
|
HTTP_TRIGGER,
|
|
18
|
+
SERVICE_BUS_CLIENT_NAME
|
|
19
19
|
)
|
|
20
20
|
from ..utils.helpers import set_sdk_version
|
|
21
|
-
from ..utils.tracing import serialize_exception_as_str
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
PB_TYPE = 'rpc_data'
|
|
@@ -87,16 +86,12 @@ def load_binding_registry() -> None:
|
|
|
87
86
|
import azurefunctions.extensions.base as clients
|
|
88
87
|
global DEFERRED_BINDING_REGISTRY
|
|
89
88
|
DEFERRED_BINDING_REGISTRY = clients.get_binding_registry()
|
|
90
|
-
except
|
|
91
|
-
|
|
92
|
-
logger.info('Base extension not found. Exception: %s. '
|
|
93
|
-
'Azure Functions library spec: %s, '
|
|
89
|
+
except ImportError:
|
|
90
|
+
logger.debug('Base extension not found. '
|
|
94
91
|
'Python version: 3.%s, Sys path: %s, '
|
|
95
92
|
'Sys Module: %s, python-packages Path exists: %s.',
|
|
96
|
-
|
|
97
|
-
sys.
|
|
98
|
-
sys.path, sys.modules,
|
|
99
|
-
os.path.exists(CUSTOMER_PACKAGES_PATH))
|
|
93
|
+
sys.version_info.minor, sys.path,
|
|
94
|
+
sys.modules, os.path.exists(CUSTOMER_PACKAGES_PATH))
|
|
100
95
|
|
|
101
96
|
|
|
102
97
|
def get_binding(bind_name: str,
|
|
@@ -292,3 +287,39 @@ def get_deferred_raw_bindings(indexed_function, input_types):
|
|
|
292
287
|
raw_bindings, bindings_logs = DEFERRED_BINDING_REGISTRY.get_raw_bindings(
|
|
293
288
|
indexed_function, input_types)
|
|
294
289
|
return raw_bindings, bindings_logs
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def get_settlement_client():
|
|
293
|
+
return DEFERRED_BINDING_REGISTRY.get(SERVICE_BUS_CLIENT_NAME).get_client()
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def validate_settlement_param(params: dict,
|
|
297
|
+
bound_params: dict,
|
|
298
|
+
annotations: dict) -> str:
|
|
299
|
+
"""
|
|
300
|
+
Checks if the settlement client is enabled for a given function.
|
|
301
|
+
|
|
302
|
+
If there is more than one param that is not bound, return an empty string
|
|
303
|
+
indicating no settlement client support. This is a bad app.
|
|
304
|
+
|
|
305
|
+
If there is only one unbound param, check if it's a type that is supported
|
|
306
|
+
by the settlement client. If so, return the param_name, where param_name
|
|
307
|
+
is the name of the param that is supported. If not, return an empty string
|
|
308
|
+
indicating no settlement client support.
|
|
309
|
+
|
|
310
|
+
Note: If a param does not have a type annotation, it will be skipped and not
|
|
311
|
+
considered for settlement client support.
|
|
312
|
+
"""
|
|
313
|
+
if len(set(params) - set(bound_params)) > 1:
|
|
314
|
+
return None
|
|
315
|
+
|
|
316
|
+
# There is only one unbound param, check the type
|
|
317
|
+
settlement_param = next(iter(set(params) - set(bound_params)))
|
|
318
|
+
try:
|
|
319
|
+
param_type = annotations.get(settlement_param)
|
|
320
|
+
# Check if the type is a supported type for the settlement client
|
|
321
|
+
if DEFERRED_BINDING_REGISTRY.check_supported_grpc_client_type(param_type):
|
|
322
|
+
return settlement_param
|
|
323
|
+
except Exception:
|
|
324
|
+
param_type = None
|
|
325
|
+
return None
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
2
|
# Licensed under the MIT License.
|
|
3
|
+
import sys
|
|
4
|
+
|
|
3
5
|
from datetime import datetime
|
|
4
6
|
from typing import Optional, Union
|
|
5
7
|
|
|
@@ -103,8 +105,18 @@ def to_nullable_timestamp(date_time: Optional[Union[datetime, int]],
|
|
|
103
105
|
int) else \
|
|
104
106
|
date_time.timestamp()
|
|
105
107
|
|
|
108
|
+
try:
|
|
109
|
+
from google.protobuf.timestamp_pb2 import Timestamp
|
|
110
|
+
except ImportError:
|
|
111
|
+
raise ImportError(
|
|
112
|
+
"protobuf not found when trying to "
|
|
113
|
+
"import Timestamp."
|
|
114
|
+
"Sys Path: %s. "
|
|
115
|
+
"Sys Modules: %s. ",
|
|
116
|
+
sys.path, sys.modules)
|
|
117
|
+
|
|
106
118
|
return protos.NullableTimestamp(
|
|
107
|
-
value=
|
|
119
|
+
value=Timestamp(seconds=int(time_in_seconds)))
|
|
108
120
|
except Exception:
|
|
109
121
|
raise TypeError(
|
|
110
122
|
"A 'datetime' or 'int'"
|
|
@@ -11,7 +11,8 @@ from .logging import logger
|
|
|
11
11
|
from .bindings.meta import (has_implicit_output,
|
|
12
12
|
check_deferred_bindings_enabled,
|
|
13
13
|
check_output_type_annotation,
|
|
14
|
-
check_input_type_annotation
|
|
14
|
+
check_input_type_annotation,
|
|
15
|
+
validate_settlement_param)
|
|
15
16
|
from .utils.constants import HTTP_TRIGGER
|
|
16
17
|
from .utils.typing_inspect import is_generic_type, get_origin, get_args # type: ignore
|
|
17
18
|
|
|
@@ -33,6 +34,7 @@ class FunctionInfo(typing.NamedTuple):
|
|
|
33
34
|
has_return: bool
|
|
34
35
|
is_http_func: bool
|
|
35
36
|
deferred_bindings_enabled: bool
|
|
37
|
+
settlement_client_arg: typing.Optional[str]
|
|
36
38
|
|
|
37
39
|
input_types: typing.Mapping[str, ParamTypeInfo]
|
|
38
40
|
output_types: typing.Mapping[str, ParamTypeInfo]
|
|
@@ -138,19 +140,27 @@ class Registry:
|
|
|
138
140
|
protos):
|
|
139
141
|
logger.debug("Params: %s, BoundParams: %s, Annotations: %s, FuncName: %s",
|
|
140
142
|
params, bound_params, annotations, func_name)
|
|
143
|
+
settlement_client_arg = None
|
|
141
144
|
if set(params) - set(bound_params):
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
# Check for settlement client support for the missing parameters
|
|
146
|
+
settlement_client_arg = validate_settlement_param(
|
|
147
|
+
params, bound_params, annotations)
|
|
148
|
+
if settlement_client_arg is not None:
|
|
149
|
+
params.pop(settlement_client_arg)
|
|
150
|
+
else:
|
|
151
|
+
# Not supported by settlement client, raise error for missing parameters
|
|
152
|
+
raise FunctionLoadError(
|
|
153
|
+
func_name,
|
|
154
|
+
'the following parameters are declared in Python '
|
|
155
|
+
'but not in the function definition (function.json or '
|
|
156
|
+
f'function decorators): {set(params) - set(bound_params)!r}')
|
|
147
157
|
|
|
148
158
|
if set(bound_params) - set(params):
|
|
149
159
|
raise FunctionLoadError(
|
|
150
160
|
func_name,
|
|
151
|
-
'Extra parameters in
|
|
152
|
-
'are
|
|
153
|
-
'
|
|
161
|
+
'Extra parameters in binding definition — the following parameters '
|
|
162
|
+
'are declared as bindings but are not '
|
|
163
|
+
'present in Python: ' + repr(set(params) - set(bound_params)))
|
|
154
164
|
|
|
155
165
|
input_types: typing.Dict[str, ParamTypeInfo] = {}
|
|
156
166
|
output_types: typing.Dict[str, ParamTypeInfo] = {}
|
|
@@ -278,7 +288,8 @@ class Registry:
|
|
|
278
288
|
output_types[param.name] = param_type_info
|
|
279
289
|
else:
|
|
280
290
|
input_types[param.name] = param_type_info
|
|
281
|
-
return input_types, output_types, fx_deferred_bindings_enabled
|
|
291
|
+
return (input_types, output_types, fx_deferred_bindings_enabled,
|
|
292
|
+
settlement_client_arg)
|
|
282
293
|
|
|
283
294
|
@staticmethod
|
|
284
295
|
def get_function_return_type(annotations: dict, has_explicit_return: bool,
|
|
@@ -289,6 +300,7 @@ class Registry:
|
|
|
289
300
|
return_anno = annotations.get('return')
|
|
290
301
|
if is_generic_type(
|
|
291
302
|
return_anno) and get_origin(
|
|
303
|
+
return_anno) is not None and get_origin(
|
|
292
304
|
return_anno).__name__ == 'Out':
|
|
293
305
|
raise FunctionLoadError(
|
|
294
306
|
func_name,
|
|
@@ -329,6 +341,7 @@ class Registry:
|
|
|
329
341
|
has_explicit_return: bool,
|
|
330
342
|
has_implicit_return: bool,
|
|
331
343
|
deferred_bindings_enabled: bool,
|
|
344
|
+
settlement_client_arg: typing.Optional[str],
|
|
332
345
|
input_types: typing.Dict[str, ParamTypeInfo],
|
|
333
346
|
output_types: typing.Dict[str, ParamTypeInfo],
|
|
334
347
|
return_type: str):
|
|
@@ -354,6 +367,7 @@ class Registry:
|
|
|
354
367
|
has_return=has_explicit_return or has_implicit_return,
|
|
355
368
|
is_http_func=is_http_func,
|
|
356
369
|
deferred_bindings_enabled=deferred_bindings_enabled,
|
|
370
|
+
settlement_client_arg=settlement_client_arg,
|
|
357
371
|
input_types=input_types,
|
|
358
372
|
output_types=output_types,
|
|
359
373
|
return_type=return_type,
|
|
@@ -411,7 +425,8 @@ class Registry:
|
|
|
411
425
|
func_name)
|
|
412
426
|
|
|
413
427
|
(input_types, output_types,
|
|
414
|
-
deferred_bindings_enabled
|
|
428
|
+
deferred_bindings_enabled,
|
|
429
|
+
settlement_client_arg) = self.validate_function_params(
|
|
415
430
|
params,
|
|
416
431
|
bound_params,
|
|
417
432
|
annotations,
|
|
@@ -430,5 +445,6 @@ class Registry:
|
|
|
430
445
|
func, func_name, function_id, func_dir,
|
|
431
446
|
requires_context, has_explicit_return,
|
|
432
447
|
has_implicit_return, deferred_bindings_enabled,
|
|
448
|
+
settlement_client_arg,
|
|
433
449
|
input_types, output_types,
|
|
434
450
|
return_type)
|
|
@@ -22,6 +22,7 @@ from .version import VERSION
|
|
|
22
22
|
|
|
23
23
|
from .bindings.context import get_context
|
|
24
24
|
from .bindings.meta import (from_incoming_proto,
|
|
25
|
+
get_settlement_client,
|
|
25
26
|
is_trigger_binding,
|
|
26
27
|
load_binding_registry,
|
|
27
28
|
to_outgoing_param_binding,
|
|
@@ -47,6 +48,7 @@ from .utils.constants import (FUNCTION_DATA_CACHE,
|
|
|
47
48
|
WORKER_OPEN_TELEMETRY_ENABLED,
|
|
48
49
|
WORKER_STATUS)
|
|
49
50
|
from .utils.executor import get_current_loop, execute_async, run_sync_func
|
|
51
|
+
from .utils.threadpool import get_threadpool_executor
|
|
50
52
|
from .utils.helpers import change_cwd, get_sdk_version, get_worker_metadata
|
|
51
53
|
from .utils.tracing import serialize_exception
|
|
52
54
|
from .utils.validators import validate_script_file_name
|
|
@@ -165,10 +167,15 @@ async def invocation_request(request):
|
|
|
165
167
|
invocation_id = invoc_request.invocation_id
|
|
166
168
|
function_id = invoc_request.function_id
|
|
167
169
|
http_v2_enabled = False
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
|
|
171
|
+
threadpool = get_threadpool_executor()
|
|
172
|
+
logger.debug(
|
|
173
|
+
"Invocation context prepared. Invocation ID: %s, Function ID: %s, "
|
|
174
|
+
"Threadpool id: %s",
|
|
175
|
+
invocation_id,
|
|
176
|
+
function_id,
|
|
177
|
+
id(threadpool) if threadpool else None,
|
|
178
|
+
)
|
|
172
179
|
|
|
173
180
|
try:
|
|
174
181
|
fi: FunctionInfo = _functions.get_function(
|
|
@@ -218,6 +225,9 @@ async def invocation_request(request):
|
|
|
218
225
|
if fi.requires_context:
|
|
219
226
|
args['context'] = fi_context
|
|
220
227
|
|
|
228
|
+
if fi.settlement_client_arg is not None:
|
|
229
|
+
args[fi.settlement_client_arg] = get_settlement_client()
|
|
230
|
+
|
|
221
231
|
if fi.output_types:
|
|
222
232
|
for name in fi.output_types:
|
|
223
233
|
args[name] = Out()
|
|
@@ -292,7 +302,7 @@ async def function_environment_reload_request(request):
|
|
|
292
302
|
This is called only when placeholder mode is true. On worker restarts
|
|
293
303
|
worker init request will be called directly.
|
|
294
304
|
"""
|
|
295
|
-
logger.debug("V2 Library Worker: received
|
|
305
|
+
logger.debug("V2 Library Worker: received FunctionEnvironmentReloadRequest, "
|
|
296
306
|
"Version %s", VERSION)
|
|
297
307
|
global _host, protos
|
|
298
308
|
try:
|
|
@@ -406,7 +416,7 @@ def index_functions(function_path: str, function_dir: str):
|
|
|
406
416
|
indexed_functions = index_function_app(function_path)
|
|
407
417
|
|
|
408
418
|
if indexed_functions:
|
|
409
|
-
|
|
419
|
+
fx_metadata_results, fx_bindings_logs = (
|
|
410
420
|
process_indexed_function(
|
|
411
421
|
protos,
|
|
412
422
|
_functions,
|
|
@@ -434,8 +444,9 @@ def index_functions(function_path: str, function_dir: str):
|
|
|
434
444
|
"function_count": len(indexed_functions),
|
|
435
445
|
"functions": " ".join(indexed_function_logs),
|
|
436
446
|
"deferred_bindings_enabled": _functions.deferred_bindings_enabled(),
|
|
437
|
-
"app_settings": get_python_appsetting_state()
|
|
447
|
+
"app_settings": get_python_appsetting_state(),
|
|
448
|
+
"azure-functions version": get_sdk_version(),
|
|
438
449
|
}
|
|
439
450
|
logger.info(json.dumps(log_data))
|
|
440
451
|
|
|
441
|
-
return
|
|
452
|
+
return fx_metadata_results
|
|
@@ -7,9 +7,9 @@ import socket
|
|
|
7
7
|
|
|
8
8
|
from typing import Any, Dict
|
|
9
9
|
|
|
10
|
-
from
|
|
10
|
+
from azure_functions_runtime.logging import logger
|
|
11
11
|
|
|
12
|
-
from
|
|
12
|
+
from azure_functions_runtime.utils.constants import (
|
|
13
13
|
X_MS_INVOCATION_ID,
|
|
14
14
|
)
|
|
15
15
|
|
|
@@ -71,7 +71,16 @@ def get_retry_settings(indexed_function):
|
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
def build_fixed_delay_retry(protos, retry, max_retry_count, retry_strategy):
|
|
74
|
-
|
|
74
|
+
try:
|
|
75
|
+
from google.protobuf.duration_pb2 import Duration
|
|
76
|
+
except ImportError:
|
|
77
|
+
raise ImportError(
|
|
78
|
+
"protobuf not found when trying to "
|
|
79
|
+
"import Duration."
|
|
80
|
+
"Sys Path: %s. "
|
|
81
|
+
"Sys Modules: %s. ",
|
|
82
|
+
sys.path, sys.modules)
|
|
83
|
+
delay_interval = Duration(
|
|
75
84
|
seconds=convert_to_seconds(retry.get(RetryPolicy.DELAY_INTERVAL.value))
|
|
76
85
|
)
|
|
77
86
|
return protos.RpcRetryOptions(
|
|
@@ -82,11 +91,20 @@ def build_fixed_delay_retry(protos, retry, max_retry_count, retry_strategy):
|
|
|
82
91
|
|
|
83
92
|
|
|
84
93
|
def build_variable_interval_retry(protos, retry, max_retry_count, retry_strategy):
|
|
85
|
-
|
|
94
|
+
try:
|
|
95
|
+
from google.protobuf.duration_pb2 import Duration
|
|
96
|
+
except ImportError:
|
|
97
|
+
raise ImportError(
|
|
98
|
+
"protobuf not found when trying to "
|
|
99
|
+
"import Duration."
|
|
100
|
+
"Sys Path: %s. "
|
|
101
|
+
"Sys Modules: %s. ",
|
|
102
|
+
sys.path, sys.modules)
|
|
103
|
+
minimum_interval = Duration(
|
|
86
104
|
seconds=convert_to_seconds(
|
|
87
105
|
retry.get(RetryPolicy.MINIMUM_INTERVAL.value))
|
|
88
106
|
)
|
|
89
|
-
maximum_interval =
|
|
107
|
+
maximum_interval = Duration(
|
|
90
108
|
seconds=convert_to_seconds(
|
|
91
109
|
retry.get(RetryPolicy.MAXIMUM_INTERVAL.value))
|
|
92
110
|
)
|
|
@@ -150,7 +168,7 @@ def process_indexed_function(protos,
|
|
|
150
168
|
message="Cannot find module. Please check the requirements.txt file for the "
|
|
151
169
|
"missing module. For more info, please refer the troubleshooting guide: "
|
|
152
170
|
+ MODULE_NOT_FOUND_TS_URL + ". Current sys.path: " + " ".join(sys.path),
|
|
153
|
-
debug_logs="Error
|
|
171
|
+
debug_logs="Error when indexing function. Sys Path:" + " ".join(sys.path)
|
|
154
172
|
+ ", python-packages Path exists: "
|
|
155
173
|
+ str(os.path.exists(CUSTOMER_PACKAGES_PATH)))
|
|
156
174
|
def index_function_app(function_path: str):
|
|
@@ -26,7 +26,7 @@ class OTelManager:
|
|
|
26
26
|
return self._azure_monitor_available
|
|
27
27
|
|
|
28
28
|
def set_otel_libs_available(self, otel_libs_available):
|
|
29
|
-
self.
|
|
29
|
+
self._otel_libs_available = otel_libs_available
|
|
30
30
|
|
|
31
31
|
def get_otel_libs_available(self):
|
|
32
32
|
return self._otel_libs_available
|
|
@@ -11,6 +11,7 @@ METADATA_PROPERTIES_WORKER_INDEXED = "worker_indexed"
|
|
|
11
11
|
MODULE_NOT_FOUND_TS_URL = "https://aka.ms/functions-modulenotfound"
|
|
12
12
|
PYTHON_LANGUAGE_RUNTIME = "python"
|
|
13
13
|
RETRY_POLICY = "retry_policy"
|
|
14
|
+
SERVICE_BUS_CLIENT_NAME = "serviceBusClient"
|
|
14
15
|
TRUE = "true"
|
|
15
16
|
TRACEPARENT = "traceparent"
|
|
16
17
|
TRACESTATE = "tracestate"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from .app_setting_manager import get_app_setting
|
|
7
|
+
from .constants import (
|
|
8
|
+
PYTHON_THREADPOOL_THREAD_COUNT,
|
|
9
|
+
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
|
|
10
|
+
PYTHON_THREADPOOL_THREAD_COUNT_MIN,
|
|
11
|
+
PYTHON_THREADPOOL_THREAD_COUNT_MAX,
|
|
12
|
+
)
|
|
13
|
+
from ..logging import logger
|
|
14
|
+
|
|
15
|
+
_threadpool_executor: Optional[ThreadPoolExecutor] = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _validate_thread_count(value: str) -> bool:
|
|
19
|
+
try:
|
|
20
|
+
int_value = int(value)
|
|
21
|
+
except ValueError:
|
|
22
|
+
logger.warning('%s must be an integer', PYTHON_THREADPOOL_THREAD_COUNT)
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
if (int_value < PYTHON_THREADPOOL_THREAD_COUNT_MIN
|
|
26
|
+
or int_value > PYTHON_THREADPOOL_THREAD_COUNT_MAX):
|
|
27
|
+
logger.warning(
|
|
28
|
+
'%s must be set to a value between %s and %s. Reverting to '
|
|
29
|
+
'default value (%s).',
|
|
30
|
+
PYTHON_THREADPOOL_THREAD_COUNT,
|
|
31
|
+
PYTHON_THREADPOOL_THREAD_COUNT_MIN,
|
|
32
|
+
PYTHON_THREADPOOL_THREAD_COUNT_MAX,
|
|
33
|
+
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
|
|
34
|
+
)
|
|
35
|
+
return False
|
|
36
|
+
return True
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _get_max_workers() -> Optional[int]:
|
|
40
|
+
threadpool_count = get_app_setting(
|
|
41
|
+
setting=PYTHON_THREADPOOL_THREAD_COUNT,
|
|
42
|
+
validator=_validate_thread_count,
|
|
43
|
+
)
|
|
44
|
+
if threadpool_count is None:
|
|
45
|
+
return None
|
|
46
|
+
try:
|
|
47
|
+
return int(threadpool_count)
|
|
48
|
+
except (TypeError, ValueError) as e:
|
|
49
|
+
logger.warning(
|
|
50
|
+
'Failed to convert %s value "%s" to integer: %s',
|
|
51
|
+
PYTHON_THREADPOOL_THREAD_COUNT, threadpool_count, e
|
|
52
|
+
)
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def start_threadpool_executor() -> None:
|
|
57
|
+
global _threadpool_executor
|
|
58
|
+
max_workers = _get_max_workers()
|
|
59
|
+
|
|
60
|
+
if _threadpool_executor is not None:
|
|
61
|
+
try:
|
|
62
|
+
_threadpool_executor.shutdown(wait=False)
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
_threadpool_executor = ThreadPoolExecutor(max_workers=max_workers)
|
|
67
|
+
logger.debug(
|
|
68
|
+
'Started threadpool executor (id=%s) with max_workers=%s',
|
|
69
|
+
id(_threadpool_executor),
|
|
70
|
+
max_workers,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def stop_threadpool_executor() -> None:
|
|
75
|
+
global _threadpool_executor
|
|
76
|
+
if _threadpool_executor is not None:
|
|
77
|
+
try:
|
|
78
|
+
_threadpool_executor.shutdown(wait=True)
|
|
79
|
+
logger.debug(
|
|
80
|
+
'Stopped threadpool executor (id=%s)',
|
|
81
|
+
id(_threadpool_executor)
|
|
82
|
+
)
|
|
83
|
+
finally:
|
|
84
|
+
_threadpool_executor = None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_threadpool_executor() -> Optional[ThreadPoolExecutor]:
|
|
88
|
+
return _threadpool_executor
|
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
# Licensed under the MIT License.
|
|
3
3
|
import traceback
|
|
4
4
|
|
|
5
|
-
from traceback import StackSummary, extract_tb
|
|
6
|
-
from typing import List
|
|
7
|
-
|
|
8
5
|
|
|
9
6
|
def extend_exception_message(exc: Exception, msg: str) -> Exception:
|
|
10
7
|
# Reconstruct exception message
|
|
11
8
|
# From: ImportModule: no module name
|
|
12
|
-
#
|
|
9
|
+
# To: ImportModule: no module name. msg
|
|
13
10
|
old_tb = exc.__traceback__
|
|
14
11
|
old_msg = getattr(exc, 'msg', None) or str(exc) or ''
|
|
15
12
|
new_msg = (old_msg.rstrip('.') + '. ' + msg).rstrip()
|
|
@@ -18,26 +15,27 @@ def extend_exception_message(exc: Exception, msg: str) -> Exception:
|
|
|
18
15
|
|
|
19
16
|
|
|
20
17
|
def marshall_exception_trace(exc: Exception) -> str:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
18
|
+
try:
|
|
19
|
+
# Use traceback.format_exception to capture the full exception chain
|
|
20
|
+
# This includes __cause__ and __context__ chained exceptions
|
|
21
|
+
full_traceback = traceback.format_exception(type(exc), exc, exc.__traceback__)
|
|
22
|
+
|
|
23
|
+
# If it's a ModuleNotFoundError, we might want to clean up the traceback
|
|
24
|
+
if isinstance(exc, ModuleNotFoundError):
|
|
25
|
+
# For consistency with the original logic, we'll still filter
|
|
26
|
+
# but we need to work with the formatted strings
|
|
27
|
+
filtered_lines = []
|
|
28
|
+
for line in full_traceback:
|
|
29
|
+
if '<frozen importlib._bootstrap>' not in line and \
|
|
30
|
+
'<frozen importlib._bootstrap_external>' not in line:
|
|
31
|
+
filtered_lines.append(line)
|
|
32
|
+
if filtered_lines:
|
|
33
|
+
return ''.join(filtered_lines)
|
|
34
|
+
|
|
35
|
+
return ''.join(full_traceback)
|
|
36
|
+
except Exception as sub_exc:
|
|
37
|
+
return (f'Could not extract traceback. '
|
|
38
|
+
f'Sub-exception: {type(sub_exc).__name__}: {str(sub_exc)}')
|
|
41
39
|
|
|
42
40
|
|
|
43
41
|
def serialize_exception(exc: Exception, protos):
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: azure-functions-runtime
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0b2
|
|
4
4
|
Summary: Python Language Worker for Azure Functions Runtime
|
|
5
5
|
Author-email: "Azure Functions team at Microsoft Corp." <azurefunctions@microsoft.com>
|
|
6
|
-
Project-URL: Documentation, https://github.com/Azure/azure-functions-python-worker/blob/dev/
|
|
6
|
+
Project-URL: Documentation, https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_runtime/README.md
|
|
7
7
|
Project-URL: Repository, https://github.com/Azure/azure-functions-python-worker
|
|
8
8
|
Keywords: azure,functions,azurefunctions,python,serverless
|
|
9
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -29,6 +29,7 @@ Requires-Dist: requests==2.*; extra == "dev"
|
|
|
29
29
|
Requires-Dist: coverage; extra == "dev"
|
|
30
30
|
Requires-Dist: grpcio~=1.70.0; extra == "dev"
|
|
31
31
|
Requires-Dist: grpcio-tools~=1.70.0; extra == "dev"
|
|
32
|
+
Requires-Dist: protobuf~=5.29.0; extra == "dev"
|
|
32
33
|
Requires-Dist: pytest-sugar; extra == "dev"
|
|
33
34
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
34
35
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
azure_functions_runtime/__init__.py
|
|
4
|
+
azure_functions_runtime/functions.py
|
|
5
|
+
azure_functions_runtime/handle_event.py
|
|
6
|
+
azure_functions_runtime/http_v2.py
|
|
7
|
+
azure_functions_runtime/loader.py
|
|
8
|
+
azure_functions_runtime/logging.py
|
|
9
|
+
azure_functions_runtime/otel.py
|
|
10
|
+
azure_functions_runtime/version.py
|
|
11
|
+
azure_functions_runtime.egg-info/PKG-INFO
|
|
12
|
+
azure_functions_runtime.egg-info/SOURCES.txt
|
|
13
|
+
azure_functions_runtime.egg-info/dependency_links.txt
|
|
14
|
+
azure_functions_runtime.egg-info/requires.txt
|
|
15
|
+
azure_functions_runtime.egg-info/top_level.txt
|
|
16
|
+
azure_functions_runtime/bindings/context.py
|
|
17
|
+
azure_functions_runtime/bindings/datumdef.py
|
|
18
|
+
azure_functions_runtime/bindings/generic.py
|
|
19
|
+
azure_functions_runtime/bindings/meta.py
|
|
20
|
+
azure_functions_runtime/bindings/nullable_converters.py
|
|
21
|
+
azure_functions_runtime/bindings/out.py
|
|
22
|
+
azure_functions_runtime/bindings/retrycontext.py
|
|
23
|
+
azure_functions_runtime/bindings/tracecontext.py
|
|
24
|
+
azure_functions_runtime/utils/__init__.py
|
|
25
|
+
azure_functions_runtime/utils/app_setting_manager.py
|
|
26
|
+
azure_functions_runtime/utils/constants.py
|
|
27
|
+
azure_functions_runtime/utils/executor.py
|
|
28
|
+
azure_functions_runtime/utils/helpers.py
|
|
29
|
+
azure_functions_runtime/utils/threadpool.py
|
|
30
|
+
azure_functions_runtime/utils/tracing.py
|
|
31
|
+
azure_functions_runtime/utils/typing_inspect.py
|
|
32
|
+
azure_functions_runtime/utils/validators.py
|
|
33
|
+
azure_functions_runtime/utils/wrappers.py
|
|
@@ -28,7 +28,7 @@ dependencies = [
|
|
|
28
28
|
]
|
|
29
29
|
|
|
30
30
|
[project.urls]
|
|
31
|
-
Documentation = "https://github.com/Azure/azure-functions-python-worker/blob/dev/
|
|
31
|
+
Documentation = "https://github.com/Azure/azure-functions-python-worker/blob/dev/azure_functions_runtime/README.md"
|
|
32
32
|
Repository = "https://github.com/Azure/azure-functions-python-worker"
|
|
33
33
|
|
|
34
34
|
[project.optional-dependencies]
|
|
@@ -41,6 +41,7 @@ dev = [
|
|
|
41
41
|
"coverage",
|
|
42
42
|
"grpcio~=1.70.0",
|
|
43
43
|
"grpcio-tools~=1.70.0",
|
|
44
|
+
"protobuf~=5.29.0",
|
|
44
45
|
"pytest-sugar",
|
|
45
46
|
"pytest-cov",
|
|
46
47
|
"pytest-xdist",
|
|
@@ -76,9 +77,9 @@ profile = "black"
|
|
|
76
77
|
line_length = 88
|
|
77
78
|
multi_line_output = 3
|
|
78
79
|
include_trailing_comma = true
|
|
79
|
-
known_first_party = ["
|
|
80
|
+
known_first_party = ["azure_functions_runtime"]
|
|
80
81
|
default_section = "THIRDPARTY"
|
|
81
|
-
src_paths = ["
|
|
82
|
+
src_paths = ["azure_functions_runtime"]
|
|
82
83
|
skip_glob = [
|
|
83
84
|
"build",
|
|
84
85
|
"dist",
|
|
@@ -99,4 +100,4 @@ skip_glob = [
|
|
|
99
100
|
]
|
|
100
101
|
|
|
101
102
|
[tool.setuptools.dynamic]
|
|
102
|
-
version = {attr = "
|
|
103
|
+
version = {attr = "azure_functions_runtime.version.VERSION"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
README.md
|
|
2
|
-
pyproject.toml
|
|
3
|
-
azure_functions_runtime.egg-info/PKG-INFO
|
|
4
|
-
azure_functions_runtime.egg-info/SOURCES.txt
|
|
5
|
-
azure_functions_runtime.egg-info/dependency_links.txt
|
|
6
|
-
azure_functions_runtime.egg-info/requires.txt
|
|
7
|
-
azure_functions_runtime.egg-info/top_level.txt
|
|
8
|
-
azure_functions_worker_v2/__init__.py
|
|
9
|
-
azure_functions_worker_v2/functions.py
|
|
10
|
-
azure_functions_worker_v2/handle_event.py
|
|
11
|
-
azure_functions_worker_v2/http_v2.py
|
|
12
|
-
azure_functions_worker_v2/loader.py
|
|
13
|
-
azure_functions_worker_v2/logging.py
|
|
14
|
-
azure_functions_worker_v2/otel.py
|
|
15
|
-
azure_functions_worker_v2/version.py
|
|
16
|
-
azure_functions_worker_v2/bindings/context.py
|
|
17
|
-
azure_functions_worker_v2/bindings/datumdef.py
|
|
18
|
-
azure_functions_worker_v2/bindings/generic.py
|
|
19
|
-
azure_functions_worker_v2/bindings/meta.py
|
|
20
|
-
azure_functions_worker_v2/bindings/nullable_converters.py
|
|
21
|
-
azure_functions_worker_v2/bindings/out.py
|
|
22
|
-
azure_functions_worker_v2/bindings/retrycontext.py
|
|
23
|
-
azure_functions_worker_v2/bindings/tracecontext.py
|
|
24
|
-
azure_functions_worker_v2/utils/__init__.py
|
|
25
|
-
azure_functions_worker_v2/utils/app_setting_manager.py
|
|
26
|
-
azure_functions_worker_v2/utils/constants.py
|
|
27
|
-
azure_functions_worker_v2/utils/executor.py
|
|
28
|
-
azure_functions_worker_v2/utils/helpers.py
|
|
29
|
-
azure_functions_worker_v2/utils/tracing.py
|
|
30
|
-
azure_functions_worker_v2/utils/typing_inspect.py
|
|
31
|
-
azure_functions_worker_v2/utils/validators.py
|
|
32
|
-
azure_functions_worker_v2/utils/wrappers.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|