From 93b892d75f5eb58c1cfc4ce131e67e3508886008 Mon Sep 17 00:00:00 2001 From: gavin-aguiar Date: Wed, 17 Apr 2024 12:40:05 -0500 Subject: [PATCH 1/8] Updating function dir in metadata resp --- azure_functions_worker/dispatcher.py | 5 +++-- azure_functions_worker/loader.py | 3 ++- .../functions_in_blueprint_only/blueprint.py | 10 ++++++++++ tests/endtoend/test_worker_process_count_functions.py | 8 ++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/azure_functions_worker/dispatcher.py b/azure_functions_worker/dispatcher.py index 3fb5f1818..5392484fd 100644 --- a/azure_functions_worker/dispatcher.py +++ b/azure_functions_worker/dispatcher.py @@ -439,8 +439,9 @@ async def _handle__function_load_request(self, request): logger.info( 'Received WorkerLoadRequest, request ID %s, function_id: %s,' - 'function_name: %s', - self.request_id, function_id, function_name) + 'function_name: %s, function_app_directory: %s', + self.request_id, function_id, function_name, + function_app_directory) programming_model = "V2" try: diff --git a/azure_functions_worker/loader.py b/azure_functions_worker/loader.py index 9bfa8ccb9..d71c5ac0c 100644 --- a/azure_functions_worker/loader.py +++ b/azure_functions_worker/loader.py @@ -27,6 +27,7 @@ _DEFAULT_SCRIPT_FILENAME = '__init__.py' _DEFAULT_ENTRY_POINT = 'main' _submodule_dirs = [] +_FUNCTION_DIRECTORY = "/home/site/wwwroot" def register_function_dir(path: PathLike) -> None: @@ -150,7 +151,7 @@ def process_indexed_function(functions_registry: functions.Registry, name=function_info.name, function_id=function_info.function_id, managed_dependency_enabled=False, # only enabled for PowerShell - directory=function_info.directory, + directory=_FUNCTION_DIRECTORY, script_file=indexed_function.function_script_file, entry_point=function_info.name, is_proxy=False, # not supported in V4 diff --git a/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py b/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py index 785049396..a8017ff30 100644 --- a/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py +++ b/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py @@ -1,4 +1,6 @@ +import datetime import logging +import time import azure.functions as func @@ -29,3 +31,11 @@ def default_template(req: func.HttpRequest) -> func.HttpResponse: " personalized response.", status_code=200 ) + + +@bp.route(route="http_func") +def http_func(req: func.HttpRequest) -> func.HttpResponse: + time.sleep(1) + + current_time = datetime.now().strftime("%H:%M:%S") + return func.HttpResponse(f"{current_time}") diff --git a/tests/endtoend/test_worker_process_count_functions.py b/tests/endtoend/test_worker_process_count_functions.py index 519d8982e..c89df2e63 100644 --- a/tests/endtoend/test_worker_process_count_functions.py +++ b/tests/endtoend/test_worker_process_count_functions.py @@ -68,3 +68,11 @@ class TestWorkerProcessCountStein(TestWorkerProcessCount): def get_script_dir(cls): return testutils.E2E_TESTS_FOLDER / 'http_functions' /\ 'http_functions_stein' + + +class TestWorkerProcessCountWithBlueprintStein(TestWorkerProcessCount): + + @classmethod + def get_script_dir(cls): + return testutils.E2E_TESTS_FOLDER / 'blueprint_functions' /\ + 'functions_in_blueprint_only' From db15dbc19250f63bf080a493f9113880f534592f Mon Sep 17 00:00:00 2001 From: gavin-aguiar Date: Wed, 17 Apr 2024 12:51:02 -0500 Subject: [PATCH 2/8] Updating test imports --- .../functions_in_blueprint_only/blueprint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py b/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py index a8017ff30..d232dcead 100644 --- a/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py +++ b/tests/endtoend/blueprint_functions/functions_in_blueprint_only/blueprint.py @@ -1,6 +1,6 @@ -import datetime import logging import time +from datetime import datetime import azure.functions as func From a2e178b176df5307434e293dc98f171b188a1e2d Mon Sep 17 00:00:00 2001 From: gavin-aguiar Date: Wed, 17 Apr 2024 14:45:02 -0500 Subject: [PATCH 3/8] Removed path hardcoding --- azure_functions_worker/dispatcher.py | 9 +++++---- azure_functions_worker/loader.py | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/azure_functions_worker/dispatcher.py b/azure_functions_worker/dispatcher.py index 5392484fd..5367f00ad 100644 --- a/azure_functions_worker/dispatcher.py +++ b/azure_functions_worker/dispatcher.py @@ -384,7 +384,7 @@ def load_function_metadata(self, function_app_directory, caller_info): script_file_name) self._function_metadata_result = ( - self.index_functions(function_path)) \ + self.index_functions(function_path, function_app_directory)) \ if os.path.exists(function_path) else None async def _handle__functions_metadata_request(self, request): @@ -439,7 +439,7 @@ async def _handle__function_load_request(self, request): logger.info( 'Received WorkerLoadRequest, request ID %s, function_id: %s,' - 'function_name: %s, function_app_directory: %s', + 'function_name: %s, function_app_directory : %s', self.request_id, function_id, function_name, function_app_directory) @@ -750,7 +750,7 @@ async def _handle__function_environment_reload_request(self, request): request_id=self.request_id, function_environment_reload_response=failure_response) - def index_functions(self, function_path: str): + def index_functions(self, function_path: str, function_dir: str): indexed_functions = loader.index_function_app(function_path) logger.info( "Indexed function app and found %s functions", @@ -761,7 +761,8 @@ def index_functions(self, function_path: str): fx_metadata_results, fx_bindings_logs = ( loader.process_indexed_function( self._functions, - indexed_functions)) + indexed_functions, + function_dir)) indexed_function_logs: List[str] = [] indexed_function_bindings_logs = [] diff --git a/azure_functions_worker/loader.py b/azure_functions_worker/loader.py index d71c5ac0c..76c2472e1 100644 --- a/azure_functions_worker/loader.py +++ b/azure_functions_worker/loader.py @@ -27,7 +27,6 @@ _DEFAULT_SCRIPT_FILENAME = '__init__.py' _DEFAULT_ENTRY_POINT = 'main' _submodule_dirs = [] -_FUNCTION_DIRECTORY = "/home/site/wwwroot" def register_function_dir(path: PathLike) -> None: @@ -122,7 +121,7 @@ def build_variable_interval_retry(retry, max_retry_count, retry_strategy): def process_indexed_function(functions_registry: functions.Registry, - indexed_functions): + indexed_functions, function_dir): """ fx_metadata_results is a list of the RpcFunctionMetadata for all the functions in the particular app. @@ -151,7 +150,7 @@ def process_indexed_function(functions_registry: functions.Registry, name=function_info.name, function_id=function_info.function_id, managed_dependency_enabled=False, # only enabled for PowerShell - directory=_FUNCTION_DIRECTORY, + directory=function_dir, script_file=indexed_function.function_script_file, entry_point=function_info.name, is_proxy=False, # not supported in V4 From 9b97a19aec83c8d3c3d306baf21c4c25e7efe716 Mon Sep 17 00:00:00 2001 From: gavin-aguiar Date: Wed, 17 Apr 2024 16:43:41 -0500 Subject: [PATCH 4/8] Added UT --- azure_functions_worker/dispatcher.py | 9 ++++++--- tests/unittests/test_dispatcher.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/azure_functions_worker/dispatcher.py b/azure_functions_worker/dispatcher.py index 5367f00ad..629eb40dc 100644 --- a/azure_functions_worker/dispatcher.py +++ b/azure_functions_worker/dispatcher.py @@ -383,9 +383,12 @@ def load_function_metadata(self, function_app_directory, caller_info): function_path = os.path.join(function_app_directory, script_file_name) - self._function_metadata_result = ( - self.index_functions(function_path, function_app_directory)) \ - if os.path.exists(function_path) else None + if not os.path.exists(function_path): + raise FileNotFoundError("function_app.py not " + f"found in {function_path}") + + self._function_metadata_result = self.index_functions( + function_path, function_app_directory) async def _handle__functions_metadata_request(self, request): metadata_request = request.functions_metadata_request diff --git a/tests/unittests/test_dispatcher.py b/tests/unittests/test_dispatcher.py index dc62acb8e..b2c8ca4fa 100644 --- a/tests/unittests/test_dispatcher.py +++ b/tests/unittests/test_dispatcher.py @@ -915,6 +915,34 @@ def test_functions_metadata_request_with_indexing_exception( metadata_response.function_metadata_response.result.status, protos.StatusResult.Failure) + @patch.dict(os.environ, {PYTHON_ENABLE_INIT_INDEXING: 'false'}) + def test_functions_metadata_request_with_filenotfound_exception(self): + + request = protos.StreamingMessage( + worker_init_request=protos.WorkerInitRequest( + host_version="2.3.4", + function_app_directory=str(FUNCTION_APP_DIRECTORY) + ) + ) + + metadata_request = protos.StreamingMessage( + functions_metadata_request=protos.FunctionsMetadataRequest( + function_app_directory="NonExistentDirectory" + ) + ) + + self.loop.run_until_complete( + self.dispatcher._handle__worker_init_request(request)) + + metadata_response = self.loop.run_until_complete( + self.dispatcher._handle__functions_metadata_request( + metadata_request)) + + self.assertEqual( + metadata_response.function_metadata_response.result.exception.message, + "FileNotFoundError: function_app.py not " + "found in NonExistentDirectory\\function_app.py") + @patch.dict(os.environ, {PYTHON_ENABLE_INIT_INDEXING: 'false'}) def test_dispatcher_indexing_in_load_request(self): init_request = protos.StreamingMessage( From ad39c325cf2e39b95f5bef7acc6bb7f9ceeb4d2c Mon Sep 17 00:00:00 2001 From: gavin-aguiar Date: Wed, 17 Apr 2024 17:17:37 -0500 Subject: [PATCH 5/8] Revert FileNotFound error --- azure_functions_worker/dispatcher.py | 11 +++++------ tests/unittests/test_dispatcher.py | 29 ---------------------------- 2 files changed, 5 insertions(+), 35 deletions(-) diff --git a/azure_functions_worker/dispatcher.py b/azure_functions_worker/dispatcher.py index 629eb40dc..2ed1b8a43 100644 --- a/azure_functions_worker/dispatcher.py +++ b/azure_functions_worker/dispatcher.py @@ -383,12 +383,11 @@ def load_function_metadata(self, function_app_directory, caller_info): function_path = os.path.join(function_app_directory, script_file_name) - if not os.path.exists(function_path): - raise FileNotFoundError("function_app.py not " - f"found in {function_path}") - - self._function_metadata_result = self.index_functions( - function_path, function_app_directory) + # For V1, the function path will not exist and + # return None. + self._function_metadata_result = ( + self.index_functions(function_path)) \ + if os.path.exists(function_path) else None async def _handle__functions_metadata_request(self, request): metadata_request = request.functions_metadata_request diff --git a/tests/unittests/test_dispatcher.py b/tests/unittests/test_dispatcher.py index b2c8ca4fa..84d72e95b 100644 --- a/tests/unittests/test_dispatcher.py +++ b/tests/unittests/test_dispatcher.py @@ -21,7 +21,6 @@ from tests.utils import testutils from tests.utils.testutils import UNIT_TESTS_ROOT - SysVersionInfo = col.namedtuple("VersionInfo", ["major", "minor", "micro", "releaselevel", "serial"]) DISPATCHER_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / 'dispatcher_functions' @@ -915,34 +914,6 @@ def test_functions_metadata_request_with_indexing_exception( metadata_response.function_metadata_response.result.status, protos.StatusResult.Failure) - @patch.dict(os.environ, {PYTHON_ENABLE_INIT_INDEXING: 'false'}) - def test_functions_metadata_request_with_filenotfound_exception(self): - - request = protos.StreamingMessage( - worker_init_request=protos.WorkerInitRequest( - host_version="2.3.4", - function_app_directory=str(FUNCTION_APP_DIRECTORY) - ) - ) - - metadata_request = protos.StreamingMessage( - functions_metadata_request=protos.FunctionsMetadataRequest( - function_app_directory="NonExistentDirectory" - ) - ) - - self.loop.run_until_complete( - self.dispatcher._handle__worker_init_request(request)) - - metadata_response = self.loop.run_until_complete( - self.dispatcher._handle__functions_metadata_request( - metadata_request)) - - self.assertEqual( - metadata_response.function_metadata_response.result.exception.message, - "FileNotFoundError: function_app.py not " - "found in NonExistentDirectory\\function_app.py") - @patch.dict(os.environ, {PYTHON_ENABLE_INIT_INDEXING: 'false'}) def test_dispatcher_indexing_in_load_request(self): init_request = protos.StreamingMessage( From 1f601653748f62ca446f96ec75b7ef9095bea047 Mon Sep 17 00:00:00 2001 From: gavin-aguiar Date: Thu, 18 Apr 2024 10:02:08 -0500 Subject: [PATCH 6/8] Added Otel flag --- azure_functions_worker/constants.py | 3 +++ azure_functions_worker/dispatcher.py | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/azure_functions_worker/constants.py b/azure_functions_worker/constants.py index fcb39ff74..69c59ad0b 100644 --- a/azure_functions_worker/constants.py +++ b/azure_functions_worker/constants.py @@ -80,3 +80,6 @@ # Base extension supported Python minor version BASE_EXT_SUPPORTED_PY_MINOR_VERSION = 8 + +PYTHON_ENABLE_OPENTELEMETRY = "PYTHON_ENABLE_OPENTELEMETRY" +PYTHON_ENABLE_OPENTELEMETRY_DEFAULT = True diff --git a/azure_functions_worker/dispatcher.py b/azure_functions_worker/dispatcher.py index 2ed1b8a43..5133e1c8c 100644 --- a/azure_functions_worker/dispatcher.py +++ b/azure_functions_worker/dispatcher.py @@ -30,7 +30,8 @@ PYTHON_SCRIPT_FILE_NAME, PYTHON_SCRIPT_FILE_NAME_DEFAULT, PYTHON_LANGUAGE_RUNTIME, PYTHON_ENABLE_INIT_INDEXING, - METADATA_PROPERTIES_WORKER_INDEXED) + METADATA_PROPERTIES_WORKER_INDEXED, PYTHON_ENABLE_OPENTELEMETRY, + PYTHON_ENABLE_OPENTELEMETRY_DEFAULT) from .extension import ExtensionManager from .http_v2 import http_coordinator, initialize_http_server, HttpV2Registry, \ sync_http_request, HttpServerInitError @@ -318,10 +319,12 @@ async def _handle__worker_init_request(self, request): constants.SHARED_MEMORY_DATA_TRANSFER: _TRUE, } - self.update_opentelemetry_status() + if get_app_setting(setting=PYTHON_ENABLE_OPENTELEMETRY, + default_value=PYTHON_ENABLE_OPENTELEMETRY_DEFAULT): + self.update_opentelemetry_status() - if self._otel_libs_available: - capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = _TRUE + if self._otel_libs_available: + capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = _TRUE if DependencyManager.should_load_cx_dependencies(): DependencyManager.prioritize_customer_dependencies() @@ -708,9 +711,12 @@ async def _handle__function_environment_reload_request(self, request): bindings.load_binding_registry() capabilities = {} - self.update_opentelemetry_status() - if self._otel_libs_available: - capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = _TRUE + if get_app_setting(setting=PYTHON_ENABLE_OPENTELEMETRY, + default_value=PYTHON_ENABLE_OPENTELEMETRY_DEFAULT): + self.update_opentelemetry_status() + + if self._otel_libs_available: + capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = _TRUE if is_envvar_true(PYTHON_ENABLE_INIT_INDEXING): try: From b6891bfea0f618bbf113dae7f46b59169470f06b Mon Sep 17 00:00:00 2001 From: gavin-aguiar Date: Thu, 18 Apr 2024 10:43:00 -0500 Subject: [PATCH 7/8] Linting fix --- azure_functions_worker/dispatcher.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/azure_functions_worker/dispatcher.py b/azure_functions_worker/dispatcher.py index 5133e1c8c..93273e1c0 100644 --- a/azure_functions_worker/dispatcher.py +++ b/azure_functions_worker/dispatcher.py @@ -30,7 +30,8 @@ PYTHON_SCRIPT_FILE_NAME, PYTHON_SCRIPT_FILE_NAME_DEFAULT, PYTHON_LANGUAGE_RUNTIME, PYTHON_ENABLE_INIT_INDEXING, - METADATA_PROPERTIES_WORKER_INDEXED, PYTHON_ENABLE_OPENTELEMETRY, + METADATA_PROPERTIES_WORKER_INDEXED, + PYTHON_ENABLE_OPENTELEMETRY, PYTHON_ENABLE_OPENTELEMETRY_DEFAULT) from .extension import ExtensionManager from .http_v2 import http_coordinator, initialize_http_server, HttpV2Registry, \ @@ -711,12 +712,14 @@ async def _handle__function_environment_reload_request(self, request): bindings.load_binding_registry() capabilities = {} - if get_app_setting(setting=PYTHON_ENABLE_OPENTELEMETRY, - default_value=PYTHON_ENABLE_OPENTELEMETRY_DEFAULT): + if get_app_setting( + setting=PYTHON_ENABLE_OPENTELEMETRY, + default_value=PYTHON_ENABLE_OPENTELEMETRY_DEFAULT): self.update_opentelemetry_status() if self._otel_libs_available: - capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = _TRUE + capabilities[constants.WORKER_OPEN_TELEMETRY_ENABLED] = ( + _TRUE) if is_envvar_true(PYTHON_ENABLE_INIT_INDEXING): try: From 4db803f3af1d159c0c05121cac41557b12cc5058 Mon Sep 17 00:00:00 2001 From: gavin-aguiar Date: Thu, 18 Apr 2024 10:52:40 -0500 Subject: [PATCH 8/8] Fixed index func --- azure_functions_worker/dispatcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_functions_worker/dispatcher.py b/azure_functions_worker/dispatcher.py index 93273e1c0..902e9d86e 100644 --- a/azure_functions_worker/dispatcher.py +++ b/azure_functions_worker/dispatcher.py @@ -390,7 +390,7 @@ def load_function_metadata(self, function_app_directory, caller_info): # For V1, the function path will not exist and # return None. self._function_metadata_result = ( - self.index_functions(function_path)) \ + self.index_functions(function_path, function_app_directory)) \ if os.path.exists(function_path) else None async def _handle__functions_metadata_request(self, request):