Azure / azure-functions-python-worker

Python worker for Azure Functions.
http://aka.ms/azurefunctions
MIT License
331 stars 100 forks source link

[Bug] dispatcher.py task factory doesn't allow for optional `context` parameter #1508

Open jreed-Aces opened 2 weeks ago

jreed-Aces commented 2 weeks ago

Expected Behavior

Python 3.11 allows for a named context parameter to be passed in when constructing a task (https://github.com/python/cpython/blob/3.11/Lib/asyncio/tasks.py#L106). However, the task factory that creates a ContextEnabledTask inside of dispatcher.py doesn't allow for that parameter. When a task is added that attempts to utilize the parameter, an error is raised instead:

System.Private.CoreLib: Exception while executing function: Functions.mention_queue_trigger. System.Private.CoreLib: Result: Failure
Exception: TypeError: Dispatcher.dispatch_forever.<locals>.<lambda>() got an unexpected keyword argument 'context'
...
File "~\Python\Python311\Lib\asyncio\base_events.py", line 449, in create_task
    task = self._task_factory(self, coro, context=context)

Actual Behavior

The task_factory lambda and the ContextEnabledTask should be able to accept the optional, named parameter of context

Steps to Reproduce

Using the existing task_factory, attempt to add a new task along with the named context parameter.

Relevant code being tried

The following fix appears to resolve the issue:

+++ b/azure_functions_worker/dispatcher.py
@@ -141,7 +141,7 @@ class Dispatcher(metaclass=DispatcherMeta):
                         worker_id=self.worker_id)))

             self._loop.set_task_factory(
-                lambda loop, coro: ContextEnabledTask(coro, loop=loop))
+                lambda loop, coro, context=None: ContextEnabledTask(coro, loop=loop, context=context))

             # Detach console logging before enabling GRPC channel logging
             logger.info('Detaching console logging.')
@@ -849,8 +849,8 @@ class AsyncLoggingHandler(logging.Handler):
 class ContextEnabledTask(asyncio.Task):
     AZURE_INVOCATION_ID = '__azure_function_invocation_id__'

-    def __init__(self, coro, loop):
-        super().__init__(coro, loop=loop)
+    def __init__(self, coro, loop, context=None):
+        super().__init__(coro, loop=loop, context = context)

         current_task = asyncio.current_task(loop)
         if current_task is not None:


### Relevant log output

_No response_

### requirements.txt file

_No response_

### Where are you facing this problem?

Local - Core Tools

### Function app name

_No response_

### Additional Information

_No response_
brbarnett commented 2 weeks ago

@jreed-Aces have you found a workaround for this? I'm having the same issue right now and you just happened to create this 2 days ago 🙂

jreed-Aces commented 2 weeks ago

@brbarnett We downgraded to Python 3.10, which doesn't have the optional context parameter. It fixes the issue, but it's far from ideal.

Locally the code fix I posted above works, but that doesn't help when deploying to Azure.

Darcos923 commented 2 weeks ago

I have the same issue with py 3.11... Fixed for the moment with py 3.10 version

dslam commented 1 week ago

ran into the same issue with python 3.11 when working on http stream mode on azure function app

TobiConti commented 6 days ago

run into the same issue using langchain Runnable method ainvoke. This worked for me but don't know why:

loop = asyncio.get_running_loop() loop.set_task_factory(None)