Skip to content

feat: Http V2 Support #1455

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 112 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from 106 commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
efc02f3
Http Proxy Support
YunchuWang Nov 9, 2023
9922b2c
final changes and tests
YunchuWang Apr 5, 2024
56d5a81
Merge branch 'dev' into wangbill/http_v2
YunchuWang Apr 5, 2024
dffc81f
fix ppl
YunchuWang Apr 5, 2024
f67698e
Merge branch 'wangbill/http_v2' of https://github.com/Azure/azure-fun…
YunchuWang Apr 5, 2024
fa52c76
revert
YunchuWang Apr 5, 2024
de028b6
fix
YunchuWang Apr 5, 2024
d5987cf
fix
YunchuWang Apr 5, 2024
2410771
fix
YunchuWang Apr 5, 2024
b78e549
fix
YunchuWang Apr 5, 2024
58e89f0
flake8
YunchuWang Apr 5, 2024
0883bb8
flake8
YunchuWang Apr 5, 2024
54bd579
flake8
YunchuWang Apr 5, 2024
e0c1308
Merge branch 'dev' into wangbill/http_v2
YunchuWang Apr 5, 2024
eb26157
only run for 3.8+
YunchuWang Apr 5, 2024
e047506
Merge https://github.com/Azure/azure-functions-python-worker into wan…
YunchuWang Apr 5, 2024
83b69c7
Merge branch 'wangbill/http_v2' of https://github.com/Azure/azure-fun…
YunchuWang Apr 5, 2024
2b99faa
FIX
YunchuWang Apr 5, 2024
5d25510
skip tests for 3.7-
YunchuWang Apr 5, 2024
4cea83a
fix
YunchuWang Apr 5, 2024
a9414d8
fix
YunchuWang Apr 5, 2024
e20b8bb
fix
YunchuWang Apr 5, 2024
64d9e18
fix
YunchuWang Apr 5, 2024
f1c780a
fix styles
YunchuWang Apr 6, 2024
bb8e77a
fix
YunchuWang Apr 6, 2024
1e66de6
s
YunchuWang Apr 6, 2024
42d7a3d
fix
YunchuWang Apr 6, 2024
21589e5
fix
YunchuWang Apr 6, 2024
69ed92d
revert
YunchuWang Apr 6, 2024
43114e7
fix
YunchuWang Apr 6, 2024
8923a44
fix
YunchuWang Apr 6, 2024
d90a2f8
fix
YunchuWang Apr 6, 2024
f44a28f
fix
YunchuWang Apr 6, 2024
b807e78
fix
YunchuWang Apr 6, 2024
ffc7a1f
fix
YunchuWang Apr 6, 2024
f53ddac
fix
YunchuWang Apr 6, 2024
d7d537b
fix
YunchuWang Apr 6, 2024
9682363
tests
YunchuWang Apr 6, 2024
a7505a0
fix
YunchuWang Apr 6, 2024
5f3565e
test
YunchuWang Apr 6, 2024
b702aaf
tests
YunchuWang Apr 6, 2024
98df5de
fix
YunchuWang Apr 6, 2024
462fad4
fix
YunchuWang Apr 6, 2024
c76c42c
fix
YunchuWang Apr 6, 2024
90a7db6
move init server
YunchuWang Apr 6, 2024
988f9ca
fix
YunchuWang Apr 7, 2024
67f679d
test
YunchuWang Apr 7, 2024
c41db16
update ppls
YunchuWang Apr 7, 2024
3f0bfb6
fix test
YunchuWang Apr 7, 2024
66f9edd
fix tests
YunchuWang Apr 7, 2024
ddc5f39
fix
YunchuWang Apr 7, 2024
5ce390a
fix
YunchuWang Apr 7, 2024
bc9ca7f
fix
YunchuWang Apr 7, 2024
680ed45
Revert "fix"
YunchuWang Apr 7, 2024
526765f
skip
YunchuWang Apr 7, 2024
4521741
fix tests
YunchuWang Apr 7, 2024
f5fff78
style
YunchuWang Apr 7, 2024
3e0075d
test
YunchuWang Apr 7, 2024
b96f74d
test
YunchuWang Apr 7, 2024
e68b41b
ff
YunchuWang Apr 7, 2024
a582688
test
YunchuWang Apr 7, 2024
d9bd32c
style
YunchuWang Apr 7, 2024
d664f65
skip
YunchuWang Apr 7, 2024
7bd566c
test
YunchuWang Apr 7, 2024
863f82b
fix
YunchuWang Apr 7, 2024
e220fc9
fix
YunchuWang Apr 7, 2024
0ea9207
fix
YunchuWang Apr 7, 2024
7e89528
replay
YunchuWang Apr 7, 2024
43b346c
f
YunchuWang Apr 7, 2024
6055378
fix
YunchuWang Apr 8, 2024
0a8f6df
codecov fix
YunchuWang Apr 8, 2024
265c821
Mount base extension to fix consumption test failures
YunchuWang Apr 8, 2024
68c2d90
style
YunchuWang Apr 8, 2024
23bd8ab
revert
YunchuWang Apr 8, 2024
aac033d
revert
YunchuWang Apr 8, 2024
259ec03
revert ppls
YunchuWang Apr 9, 2024
4142767
test
hallvictoria Apr 9, 2024
3915493
Revert "test"
hallvictoria Apr 9, 2024
ec42efc
address feedback
YunchuWang Apr 10, 2024
7333a02
revert ut ppl
YunchuWang Apr 10, 2024
99a47a2
skip checking has http func
YunchuWang Apr 10, 2024
9221846
fix test
YunchuWang Apr 10, 2024
a70ca75
style
YunchuWang Apr 10, 2024
f7e136b
revert cache ppl
YunchuWang Apr 10, 2024
16945e5
revert ppl
YunchuWang Apr 10, 2024
0d9b5ca
pip fix
YunchuWang Apr 10, 2024
efbeff3
try fix 3.7 ppl
YunchuWang Apr 10, 2024
b49fc06
try
YunchuWang Apr 10, 2024
5b8af9e
oh meta
YunchuWang Apr 10, 2024
ae97bea
fix
YunchuWang Apr 10, 2024
6f01bcb
fix
YunchuWang Apr 10, 2024
797f716
fix
YunchuWang Apr 10, 2024
de0cc98
dont pin fastapi to fix cmake err
YunchuWang Apr 10, 2024
e617340
fix
YunchuWang Apr 10, 2024
e28d769
fix
YunchuWang Apr 10, 2024
88c0896
Merge branch 'dev' into wangbill/http_v2
YunchuWang Apr 10, 2024
295bf90
Merge branch 'dev' into wangbill/http_v2
YunchuWang Apr 10, 2024
7449d0d
update azfunc base
YunchuWang Apr 11, 2024
450b43e
update
YunchuWang Apr 11, 2024
3ab30f7
feedback
YunchuWang Apr 11, 2024
e85ea9e
feedback
YunchuWang Apr 11, 2024
a695ba3
feedback
YunchuWang Apr 11, 2024
62d7bac
add docs
YunchuWang Apr 11, 2024
7a8ce47
Merge branch 'dev' into wangbill/http_v2
YunchuWang Apr 12, 2024
142b5ce
merge fix
YunchuWang Apr 12, 2024
c19172f
Merge branch 'dev' into wangbill/http_v2
YunchuWang Apr 12, 2024
8d8e4ab
Merge branch 'dev' into wangbill/http_v2
YunchuWang Apr 12, 2024
3608c23
feedback
YunchuWang Apr 12, 2024
c4a8af1
Merge branch 'wangbill/http_v2' of https://github.com/Azure/azure-fun…
YunchuWang Apr 12, 2024
a20ff5c
feedback
YunchuWang Apr 12, 2024
15ba6b4
feedback
YunchuWang Apr 12, 2024
87399e7
feedback
YunchuWang Apr 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci_consumption_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ jobs:
python -m pip install --upgrade pip
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple -U azure-functions --pre
python -m pip install -U -e .[dev]
if [[ "${{ matrix.python-version }}" != "3.7" ]]; then
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple --pre -U -e .[test-http-v2]
fi
python setup.py build
- name: Running 3.7 Tests
if: matrix.python-version == 3.7
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/ci_e2e_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ jobs:
python -m pip install --upgrade pip
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple -U azure-functions --pre
python -m pip install -U -e .[dev]

if [[ "${{ matrix.python-version }}" != "3.7" ]]; then
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple --pre -U -e .[test-http-v2]
fi
if [[ "${{ matrix.python-version }}" != "3.7" && "${{ matrix.python-version }}" != "3.8" ]]; then
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple --pre -U -e .[test-deferred-bindings]
fi
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/ci_ut_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ jobs:

python -m pip install --upgrade pip
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple -U azure-functions --pre
python -m pip install -U -e .[dev]

python -m pip install -U -e .[dev]
if [[ "${{ matrix.python-version }}" != "3.7" ]]; then
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple --pre -U -e .[test-http-v2]
fi

# Retry a couple times to avoid certificate issue
retry 5 python setup.py build
Expand Down
42 changes: 41 additions & 1 deletion azure_functions_worker/bindings/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
import sys
import typing

from .. import protos
from azure_functions_worker.constants import HTTP, HTTP_TRIGGER

from .. import protos
from . import datumdef
from . import generic

from .shared_memory_data_transfer import SharedMemoryManager
from ..http_v2 import HttpV2Registry
from ..constants import CUSTOMER_PACKAGES_PATH
from ..logging import logger


PB_TYPE = 'rpc_data'
PB_TYPE_DATA = 'data'
PB_TYPE_RPC_SHARED_MEMORY = 'rpc_shared_memory'
Expand All @@ -24,6 +27,33 @@
deferred_bindings_cache = {}


def _check_http_input_type_annotation(bind_name: str, pytype: type,
is_deferred_binding: bool) -> bool:
if HttpV2Registry.http_v2_enabled():
return HttpV2Registry.ext_base().RequestTrackerMeta \
.check_type(pytype)

binding = get_binding(bind_name, is_deferred_binding)
return binding.check_input_type_annotation(pytype)


def _check_http_output_type_annotation(bind_name: str, pytype: type) -> bool:
if HttpV2Registry.http_v2_enabled():
return HttpV2Registry.ext_base().ResponseTrackerMeta.check_type(pytype)

binding = get_binding(bind_name)
return binding.check_output_type_annotation(pytype)


INPUT_TYPE_CHECK_OVERRIDE_MAP = {
HTTP_TRIGGER: _check_http_input_type_annotation
}

OUTPUT_TYPE_CHECK_OVERRIDE_MAP = {
HTTP: _check_http_output_type_annotation
}


def load_binding_registry() -> None:
"""
Tries to load azure-functions from the customer's BYO. If it's
Expand Down Expand Up @@ -89,11 +119,21 @@ def is_trigger_binding(bind_name: str) -> bool:
def check_input_type_annotation(bind_name: str,
pytype: type,
is_deferred_binding: bool) -> bool:
global INPUT_TYPE_CHECK_OVERRIDE_MAP
if bind_name in INPUT_TYPE_CHECK_OVERRIDE_MAP:
return INPUT_TYPE_CHECK_OVERRIDE_MAP[bind_name](bind_name, pytype,
is_deferred_binding)

binding = get_binding(bind_name, is_deferred_binding)

return binding.check_input_type_annotation(pytype)


def check_output_type_annotation(bind_name: str, pytype: type) -> bool:
global OUTPUT_TYPE_CHECK_OVERRIDE_MAP
if bind_name in OUTPUT_TYPE_CHECK_OVERRIDE_MAP:
return OUTPUT_TYPE_CHECK_OVERRIDE_MAP[bind_name](bind_name, pytype)

binding = get_binding(bind_name)
return binding.check_output_type_annotation(pytype)

Expand Down
16 changes: 15 additions & 1 deletion azure_functions_worker/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
WORKER_STATUS = "WorkerStatus"
SHARED_MEMORY_DATA_TRANSFER = "SharedMemoryDataTransfer"
FUNCTION_DATA_CACHE = "FunctionDataCache"
HTTP_URI = "HttpUri"

# Platform Environment Variables
AZURE_WEBJOBS_SCRIPT_ROOT = "AzureWebJobsScriptRoot"
Expand Down Expand Up @@ -54,9 +55,22 @@
RETRY_POLICY = "retry_policy"

# Paths
CUSTOMER_PACKAGES_PATH = "/home/site/wwwroot/.python_packages/lib/site-packages"
CUSTOMER_PACKAGES_PATH = "/home/site/wwwroot/.python_packages/lib/site" \
"-packages"

# Flag to index functions in handle init request
PYTHON_ENABLE_INIT_INDEXING = "PYTHON_ENABLE_INIT_INDEXING"

METADATA_PROPERTIES_WORKER_INDEXED = "worker_indexed"

# Header names
X_MS_INVOCATION_ID = "x-ms-invocation-id"

# Trigger Names
HTTP_TRIGGER = "httpTrigger"

# Output Names
HTTP = "http"

# Base extension supported Python minor version
BASE_EXT_SUPPORTED_PY_MINOR_VERSION = 8
74 changes: 58 additions & 16 deletions azure_functions_worker/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from datetime import datetime

import grpc

from . import bindings, constants, functions, loader, protos
from .bindings.shared_memory_data_transfer import SharedMemoryManager
from .constants import (PYTHON_ROLLBACK_CWD_PATH,
Expand All @@ -32,7 +31,10 @@
PYTHON_SCRIPT_FILE_NAME_DEFAULT,
PYTHON_LANGUAGE_RUNTIME, PYTHON_ENABLE_INIT_INDEXING,
METADATA_PROPERTIES_WORKER_INDEXED)
from .exceptions import HttpServerInitError
from .extension import ExtensionManager
from .http_v2 import http_coordinator, initialize_http_server, HttpV2Registry, \
sync_http_request
from .logging import disable_console_logging, enable_console_logging
from .logging import (logger, error_logger, is_system_log_category,
CONSOLE_LOG_PREFIX, format_exception)
Expand Down Expand Up @@ -158,6 +160,7 @@ async def dispatch_forever(self): # sourcery skip: swap-if-expression

log_level = logging.INFO if not is_envvar_true(
PYTHON_ENABLE_DEBUG_LOGGING) else logging.DEBUG

root_logger.setLevel(log_level)
root_logger.addHandler(logging_handler)
logger.info('Switched to gRPC logging.')
Expand Down Expand Up @@ -189,7 +192,8 @@ def stop(self) -> None:

self._stop_sync_call_tp()

def on_logging(self, record: logging.LogRecord, formatted_msg: str) -> None:
def on_logging(self, record: logging.LogRecord,
formatted_msg: str) -> None:
if record.levelno >= logging.CRITICAL:
log_level = protos.RpcLog.Critical
elif record.levelno >= logging.ERROR:
Expand Down Expand Up @@ -306,6 +310,13 @@ async def _handle__worker_init_request(self, request):
self.load_function_metadata(
worker_init_request.function_app_directory,
caller_info="worker_init_request")

if HttpV2Registry.http_v2_enabled():
capabilities[constants.HTTP_URI] = \
initialize_http_server(self._host)

except HttpServerInitError:
raise
except Exception as ex:
self._function_metadata_exception = ex

Expand Down Expand Up @@ -508,6 +519,7 @@ async def _handle__invocation_request(self, request):
logger.info(', '.join(function_invocation_logs))

args = {}

for pb in invoc_request.input_data:
pb_type_info = fi.input_types[pb.name]
if bindings.is_trigger_binding(pb_type_info.binding_name):
Expand All @@ -523,7 +535,19 @@ async def _handle__invocation_request(self, request):
shmem_mgr=self._shmem_mgr,
is_deferred_binding=pb_type_info.deferred_bindings_enabled)

fi_context = self._get_context(invoc_request, fi.name, fi.directory)
http_v2_enabled = self._functions.get_function(function_id) \
.is_http_func and \
HttpV2Registry.http_v2_enabled()

if http_v2_enabled:
http_request = await http_coordinator.get_http_request_async(
invocation_id)

await sync_http_request(http_request, invoc_request)
args[fi.trigger_metadata.get('param_name')] = http_request

fi_context = self._get_context(invoc_request, fi.name,
fi.directory)

# Use local thread storage to store the invocation ID
# for a customer's threads
Expand All @@ -536,17 +560,21 @@ async def _handle__invocation_request(self, request):
args[name] = bindings.Out()

if fi.is_async:
call_result = await self._run_async_func(
fi_context, fi.func, args
)
call_result = \
await self._run_async_func(fi_context, fi.func, args)
else:
call_result = await self._loop.run_in_executor(
self._sync_call_tp,
self._run_sync_func,
invocation_id, fi_context, fi.func, args)

if call_result is not None and not fi.has_return:
raise RuntimeError(f'function {fi.name!r} without a $return '
'binding returned a non-None value')
raise RuntimeError(
f'function {fi.name!r} without a $return binding'
'returned a non-None value')

if http_v2_enabled:
http_coordinator.set_http_response(invocation_id, call_result)

output_data = []
cache_enabled = self._function_data_cache_enabled
Expand All @@ -566,10 +594,12 @@ async def _handle__invocation_request(self, request):
output_data.append(param_binding)

return_value = None
if fi.return_type is not None:
if fi.return_type is not None and not http_v2_enabled:
return_value = bindings.to_outgoing_proto(
fi.return_type.binding_name, call_result,
pytype=fi.return_type.pytype)
fi.return_type.binding_name,
call_result,
pytype=fi.return_type.pytype,
)

# Actively flush customer print() function to console
sys.stdout.flush()
Expand All @@ -584,6 +614,9 @@ async def _handle__invocation_request(self, request):
output_data=output_data))

except Exception as ex:
if http_v2_enabled:
http_coordinator.set_http_response(invocation_id, ex)

return protos.StreamingMessage(
request_id=self.request_id,
invocation_response=protos.InvocationResponse(
Expand Down Expand Up @@ -640,11 +673,18 @@ async def _handle__function_environment_reload_request(self, request):
# reload_customer_libraries call clears the registry
bindings.load_binding_registry()

capabilities = {}
if is_envvar_true(PYTHON_ENABLE_INIT_INDEXING):
try:
self.load_function_metadata(
directory,
caller_info="environment_reload_request")

if HttpV2Registry.http_v2_enabled():
capabilities[constants.HTTP_URI] = \
initialize_http_server(self._host)
except HttpServerInitError:
raise
except Exception as ex:
self._function_metadata_exception = ex

Expand All @@ -655,7 +695,7 @@ async def _handle__function_environment_reload_request(self, request):
func_env_reload_request.function_app_directory)

success_response = protos.FunctionEnvironmentReloadResponse(
capabilities={},
capabilities=capabilities,
worker_metadata=self.get_worker_metadata(),
result=protos.StatusResult(
status=protos.StatusResult.Success))
Expand All @@ -676,8 +716,10 @@ async def _handle__function_environment_reload_request(self, request):

def index_functions(self, function_path: str):
indexed_functions = loader.index_function_app(function_path)
logger.info('Indexed function app and found %s functions',
len(indexed_functions))
logger.info(
"Indexed function app and found %s functions",
len(indexed_functions)
)

if indexed_functions:
fx_metadata_results, fx_bindings_logs = (
Expand Down Expand Up @@ -747,7 +789,8 @@ async def _handle__close_shared_memory_resources_request(self, request):
@staticmethod
def _get_context(invoc_request: protos.InvocationRequest, name: str,
directory: str) -> bindings.Context:
""" For more information refer: https://aka.ms/azfunc-invocation-context
""" For more information refer:
https://aka.ms/azfunc-invocation-context
"""
trace_context = bindings.TraceContext(
invoc_request.trace_context.trace_parent,
Expand Down Expand Up @@ -889,7 +932,6 @@ def gen(resp_queue):


class AsyncLoggingHandler(logging.Handler):

def emit(self, record: LogRecord) -> None:
# Since we disable console log after gRPC channel is initiated,
# we should redirect all the messages into dispatcher.
Expand Down
9 changes: 9 additions & 0 deletions azure_functions_worker/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# http v2 exception types
class HttpServerInitError(Exception):
"""Exception raised when there is an error during HTTP server
initialization."""


class MissingHeaderError(ValueError):
"""Exception raised when a required header is missing in the
HTTP request."""
Loading
Loading