Skip to content

Commit 52dd1f5

Browse files
authored
fix: Py3.13+ logging issue with operation_Name (#1811)
* Py3.13+ logging fix * Added runtime check for backward compatibility * Fixed flake8 error * ``
1 parent 715a9dc commit 52dd1f5

File tree

6 files changed

+41
-10
lines changed

6 files changed

+41
-10
lines changed

runtimes/v1/azure_functions_runtime_v1/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
stop_threadpool_executor,
1212
get_threadpool_executor,
1313
)
14+
from .utils.executor import invocation_id_cv
1415

1516
__all__ = ('worker_init_request',
1617
'functions_metadata_request',
@@ -19,4 +20,5 @@
1920
'function_load_request',
2021
'start_threadpool_executor',
2122
'stop_threadpool_executor',
22-
'get_threadpool_executor')
23+
'get_threadpool_executor',
24+
'invocation_id_cv')

runtimes/v1/azure_functions_runtime_v1/utils/executor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Licensed under the MIT License.
33

44
import asyncio
5+
import contextvars
56
import functools
67

78
from typing import Any
@@ -21,14 +22,19 @@ def execute_sync(function, args) -> Any:
2122
return function(**args)
2223

2324

25+
invocation_id_cv = contextvars.ContextVar('invocation_id', default=None)
26+
27+
2428
def run_sync_func(invocation_id, context, func, params):
2529
# This helper exists because we need to access the current
2630
# invocation_id from ThreadPoolExecutor's threads.
2731
context.thread_local_storage.invocation_id = invocation_id
32+
token = invocation_id_cv.set(invocation_id)
2833
try:
2934
if otel_manager.get_azure_monitor_available():
3035
configure_opentelemetry(context)
3136
result = functools.partial(execute_sync, func)
3237
return result(params)
3338
finally:
39+
invocation_id_cv.reset(token)
3440
context.thread_local_storage.invocation_id = None

runtimes/v2/azure_functions_runtime/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
stop_threadpool_executor,
1111
get_threadpool_executor,
1212
)
13+
from .utils.executor import invocation_id_cv
1314

1415
__all__ = ('worker_init_request',
1516
'functions_metadata_request',
@@ -18,4 +19,5 @@
1819
'function_load_request',
1920
'start_threadpool_executor',
2021
'stop_threadpool_executor',
21-
'get_threadpool_executor')
22+
'get_threadpool_executor',
23+
'invocation_id_cv')

runtimes/v2/azure_functions_runtime/utils/executor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33
import asyncio
4+
import contextvars
45
import functools
56

67
from typing import Any
@@ -20,15 +21,20 @@ def execute_sync(function, args) -> Any:
2021
return function(**args)
2122

2223

24+
invocation_id_cv = contextvars.ContextVar('invocation_id', default=None)
25+
26+
2327
def run_sync_func(invocation_id, context, func, params):
2428
# This helper exists because we need to access the current
2529
# invocation_id from ThreadPoolExecutor's threads.
2630
context.thread_local_storage.invocation_id = invocation_id
31+
token = invocation_id_cv.set(invocation_id)
2732
try:
2833
if (otel_manager.get_azure_monitor_available()
2934
or otel_manager.get_otel_libs_available()):
3035
configure_opentelemetry(context)
3136
result = functools.partial(execute_sync, func)
3237
return result(params)
3338
finally:
39+
invocation_id_cv.reset(token)
3440
context.thread_local_storage.invocation_id = None

workers/proxy_worker/dispatcher.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from typing import Any, Optional
1515

1616
import grpc
17+
from packaging.version import Version
18+
1719
from proxy_worker import protos
1820
from proxy_worker.logging import (
1921
CONSOLE_LOG_PREFIX,
@@ -32,7 +34,6 @@
3234
PYTHON_ENABLE_DEBUG_LOGGING,
3335
)
3436
from proxy_worker.version import VERSION
35-
3637
from .utils.dependency import DependencyManager
3738

3839
# Library worker import reloaded in init and reload request
@@ -99,10 +100,13 @@ def get_global_current_invocation_id() -> Optional[str]:
99100

100101

101102
def get_current_invocation_id() -> Optional[Any]:
103+
global _library_worker
102104
# Check global current invocation first (most up-to-date)
103-
global_invocation_id = get_global_current_invocation_id()
104-
if global_invocation_id is not None:
105-
return global_invocation_id
105+
if (_library_worker
106+
and Version(_library_worker.version.VERSION) < Version("1.1.0b4")):
107+
global_invocation_id = get_global_current_invocation_id()
108+
if global_invocation_id is not None:
109+
return global_invocation_id
106110

107111
# Check asyncio task context
108112
try:
@@ -125,6 +129,17 @@ def get_current_invocation_id() -> Optional[Any]:
125129
if thread_invocation_id is not None:
126130
return thread_invocation_id
127131

132+
# Check contextvar from library worker
133+
if _library_worker:
134+
try:
135+
cv = getattr(_library_worker, 'invocation_id_cv', None)
136+
if cv:
137+
val = cv.get()
138+
if val is not None:
139+
return val
140+
except (AttributeError, LookupError):
141+
pass
142+
128143
return getattr(_invocation_id_local, 'invocation_id', None)
129144

130145

workers/tests/unittest_proxy/test_dispatcher.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,8 @@ def test_thread_invocation_registry(self):
460460
# Test clear non-existent (should not raise)
461461
clear_thread_invocation_id(99999)
462462

463-
def test_get_current_invocation_id_priority_global(self):
464-
"""Test that global invocation ID has highest priority"""
463+
def test_get_current_invocation_id_ignores_global_by_default(self):
464+
"""Test that global invocation ID is ignored by default"""
465465
global_id = "global-123"
466466
thread_id = threading.get_ident()
467467
thread_id_value = "thread-456"
@@ -470,9 +470,9 @@ def test_get_current_invocation_id_priority_global(self):
470470
set_current_invocation_id(global_id)
471471
set_thread_invocation_id(thread_id, thread_id_value)
472472

473-
# Global should take priority
473+
# Thread should take priority (global is ignored)
474474
result = get_current_invocation_id()
475-
self.assertEqual(result, global_id)
475+
self.assertEqual(result, thread_id_value)
476476

477477
def test_get_current_invocation_id_fallback_to_thread(self):
478478
"""Test fallback to thread registry when global is None"""

0 commit comments

Comments
 (0)