Skip to content

Commit ceac558

Browse files
fix: Http V2 route params update (#1491)
* Http V2 route params update Worker Changes to get route parameters of http invocation request from invocation request "route_params" attributes after host made update in Azure/azure-functions-host#9997. TODO: Update lc test after lc image released with host version containing the change. * test: add unit tests * chore: fix linting * fix: linting --------- Co-authored-by: gavin-aguiar <[email protected]>
1 parent b734c57 commit ceac558

File tree

4 files changed

+74
-11
lines changed

4 files changed

+74
-11
lines changed

azure_functions_worker/constants.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
SHARED_MEMORY_DATA_TRANSFER = "SharedMemoryDataTransfer"
1212
FUNCTION_DATA_CACHE = "FunctionDataCache"
1313
HTTP_URI = "HttpUri"
14-
14+
REQUIRES_ROUTE_PARAMETERS = "RequiresRouteParameters"
1515
# When this capability is enabled, logs are not piped back to the
1616
# host from the worker. Logs will directly go to where the user has
1717
# configured them to go. This is to ensure that the logs are not

azure_functions_worker/dispatcher.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
4040
PYTHON_THREADPOOL_THREAD_COUNT_MAX_37,
4141
PYTHON_THREADPOOL_THREAD_COUNT_MIN,
42+
REQUIRES_ROUTE_PARAMETERS,
43+
HTTP_URI
4244
)
4345
from .extension import ExtensionManager
4446
from .http_v2 import (
@@ -403,8 +405,9 @@ async def _handle__worker_init_request(self, request):
403405
caller_info="worker_init_request")
404406

405407
if HttpV2Registry.http_v2_enabled():
406-
capabilities[constants.HTTP_URI] = \
408+
capabilities[HTTP_URI] = \
407409
initialize_http_server(self._host)
410+
capabilities[REQUIRES_ROUTE_PARAMETERS] = _TRUE
408411

409412
except HttpServerInitError:
410413
raise
@@ -640,8 +643,10 @@ async def _handle__invocation_request(self, request):
640643
http_request = await http_coordinator.get_http_request_async(
641644
invocation_id)
642645

643-
await sync_http_request(http_request, invoc_request)
644-
args[fi.trigger_metadata.get('param_name')] = http_request
646+
trigger_arg_name = fi.trigger_metadata.get('param_name')
647+
func_http_request = args[trigger_arg_name]
648+
await sync_http_request(http_request, func_http_request)
649+
args[trigger_arg_name] = http_request
645650

646651
fi_context = self._get_context(invoc_request, fi.name,
647652
fi.directory)
@@ -790,8 +795,9 @@ async def _handle__function_environment_reload_request(self, request):
790795
caller_info="environment_reload_request")
791796

792797
if HttpV2Registry.http_v2_enabled():
793-
capabilities[constants.HTTP_URI] = \
798+
capabilities[HTTP_URI] = \
794799
initialize_http_server(self._host)
800+
capabilities[REQUIRES_ROUTE_PARAMETERS] = _TRUE
795801
except HttpServerInitError:
796802
raise
797803
except Exception as ex:

azure_functions_worker/http_v2.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,11 @@ async def catch_all(request: request_type): # type: ignore
246246
from e
247247

248248

249-
async def sync_http_request(http_request, invoc_request):
249+
async def sync_http_request(http_request, func_http_request):
250250
# Sync http request route params from invoc_request to http_request
251-
route_params = {key: item.string for key, item
252-
in invoc_request.trigger_metadata.items()
253-
if key not in ['Headers', 'Query']}
254251
(HttpV2Registry.ext_base().RequestTrackerMeta
255252
.get_synchronizer()
256-
.sync_route_params(http_request, route_params))
253+
.sync_route_params(http_request, func_http_request.route_params))
257254

258255

259256
class HttpV2Registry:

tests/unittests/test_dispatcher.py

+61-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
PYTHON_THREADPOOL_THREAD_COUNT,
2121
PYTHON_THREADPOOL_THREAD_COUNT_DEFAULT,
2222
PYTHON_THREADPOOL_THREAD_COUNT_MAX_37,
23-
PYTHON_THREADPOOL_THREAD_COUNT_MIN,
23+
PYTHON_THREADPOOL_THREAD_COUNT_MIN, HTTP_URI, REQUIRES_ROUTE_PARAMETERS,
2424
)
2525
from azure_functions_worker.dispatcher import Dispatcher, ContextEnabledTask
2626
from azure_functions_worker.version import VERSION
@@ -33,6 +33,8 @@
3333
'dispatcher_functions_stein'
3434
FUNCTION_APP_DIRECTORY = UNIT_TESTS_ROOT / 'dispatcher_functions' / \
3535
'dispatcher_functions_stein'
36+
HTTPV2_FUNCTION_APP_DIRECTORY = UNIT_TESTS_ROOT / 'dispatcher_functions' / \
37+
'http_v2' / 'fastapi'
3638

3739

3840
class TestThreadPoolSettingsPython37(testutils.AsyncTestCase):
@@ -767,6 +769,7 @@ def setUp(self):
767769
asyncio.set_event_loop(self.loop)
768770
self.dispatcher = testutils.create_dummy_dispatcher()
769771
sys.path.append(str(FUNCTION_APP_DIRECTORY))
772+
sys.path.append(str(HTTPV2_FUNCTION_APP_DIRECTORY))
770773

771774
def tearDown(self):
772775
self.loop.close()
@@ -991,6 +994,63 @@ def test_dispatcher_indexing_in_load_request_with_exception(
991994
response.function_load_response.result.exception.message,
992995
"Exception: Mocked Exception")
993996

997+
@patch.dict(os.environ, {PYTHON_ENABLE_INIT_INDEXING: 'true'})
998+
@patch("azure_functions_worker.http_v2.HttpV2Registry.http_v2_enabled",
999+
return_value=True)
1000+
def test_dispatcher_http_v2_init_request_fail(self, mock_http_v2_enabled):
1001+
request = protos.StreamingMessage(
1002+
worker_init_request=protos.WorkerInitRequest(
1003+
host_version="2.3.4",
1004+
function_app_directory=str(HTTPV2_FUNCTION_APP_DIRECTORY)
1005+
)
1006+
)
1007+
1008+
resp = self.loop.run_until_complete(
1009+
self.dispatcher._handle__worker_init_request(request)
1010+
)
1011+
1012+
mock_http_v2_enabled.assert_called_once()
1013+
self.assertIsNotNone(self.dispatcher._function_metadata_exception)
1014+
1015+
capabilities = resp.worker_init_response.capabilities
1016+
self.assertNotIn(HTTP_URI, capabilities)
1017+
self.assertNotIn(REQUIRES_ROUTE_PARAMETERS, capabilities)
1018+
1019+
# Cleanup
1020+
del sys.modules['function_app']
1021+
1022+
@patch.dict(os.environ, {PYTHON_ENABLE_INIT_INDEXING: 'true'})
1023+
@patch("azure_functions_worker.http_v2.HttpV2Registry.http_v2_enabled",
1024+
return_value=True)
1025+
@patch("azure_functions_worker.dispatcher.initialize_http_server",
1026+
return_value="http://localhost:8080")
1027+
@patch("azure_functions_worker.dispatcher.Dispatcher"
1028+
".load_function_metadata")
1029+
def test_dispatcher_http_v2_init_request_pass(self, mock_http_v2_enabled,
1030+
mock_init_http_server,
1031+
mock_load_func_metadata):
1032+
request = protos.StreamingMessage(
1033+
worker_init_request=protos.WorkerInitRequest(
1034+
host_version="2.3.4",
1035+
function_app_directory=str(HTTPV2_FUNCTION_APP_DIRECTORY)
1036+
)
1037+
)
1038+
1039+
resp = self.loop.run_until_complete(
1040+
self.dispatcher._handle__worker_init_request(request)
1041+
)
1042+
1043+
mock_http_v2_enabled.assert_called_once()
1044+
mock_init_http_server.assert_called_once()
1045+
mock_load_func_metadata.assert_called_once()
1046+
self.assertIsNone(self.dispatcher._function_metadata_exception)
1047+
1048+
capabilities = resp.worker_init_response.capabilities
1049+
self.assertIn(HTTP_URI, capabilities)
1050+
self.assertEqual(capabilities[HTTP_URI], "http://localhost:8080")
1051+
self.assertIn(REQUIRES_ROUTE_PARAMETERS, capabilities)
1052+
self.assertEqual(capabilities[REQUIRES_ROUTE_PARAMETERS], "true")
1053+
9941054

9951055
class TestContextEnabledTask(unittest.TestCase):
9961056
def setUp(self):

0 commit comments

Comments
 (0)