OpenFunction icon indicating copy to clipboard operation
OpenFunction copied to clipboard

Unable to create a python function with asynchronous bindings

Open grigorizaika1 opened this issue 2 years ago • 2 comments

Description The README in functions-framework-python says that synchronous functions backed by the Knative runtime can now interact with middlewares defined by Dapr output binding or pub/sub.

I'm trying to run the hello-world example for python with one modification: I add an output binding to it. I'm using the Go example and going by analogy.

Now if I'm not mistaken, in order to actually interact with the output binding, we have to call the send on a DaprRuntime object. And in order to access DaprRuntime, we need to install the python framework, similarly to what the go example does with the go framework. The installation of the framework also requires dapr-ext-grpc, otherwise the function doesn't even start serving.

The issue is as follows: If you add functions-framework-python and dapr-ext-grpc to the requirements, the function gets built and runs. But if you send a POST request to it, you'll receive an error (500) in the function response, and the grpc._channel._InactiveRpcError in the logs.

Am I using the library the wrong way? I don't see any different way to access the bindings, and this way renders async and sync with bindings unusable for python.

Environment

  • Operating System Information: tried MacOs Ventura 13.0 (M1, arm), and Ubuntu 22.04 LTS (i7, Intel)
  • kubernetes version: 1.20
  • OpenFunction version: 0.8.1
  • Versions of dependent components: Dapr 1.8.3, Keda: 2.8.1, Knative 1.3.2

Expected behavior

  1. Should be able to use the DaprRuntime objects to send messages to the output binding
  2. The function should return the hello world message and a success status

Actual behavior The function returns 500 when POSTed to.

The functoin logs say:

 Traceback (most recent call last):
2023-01-23T18:19:32.693Z    File "/layers/google.python.pip/pip/lib/python3.10/site-packages/flask/app.py", line 1844, in finalize_request
2023-01-23T18:19:32.693Z      response = self.process_response(response)
2023-01-23T18:19:32.693Z    File "/layers/google.python.pip/pip/lib/python3.10/site-packages/flask/app.py", line 2337, in process_response
2023-01-23T18:19:32.693Z      response = self.ensure_sync(func)(response)
2023-01-23T18:19:32.693Z    File "/layers/google.python.pip/pip/lib/python3.10/site-packages/openfunction/dapr_output_middleware.py", line 12, in dapr_output_middleware
2023-01-23T18:19:32.693Z      resp = runtime.send(response.get_data(True))
2023-01-23T18:19:32.693Z    File "/layers/google.python.pip/pip/lib/python3.10/site-packages/openfunction/function_runtime.py", line 79, in send
2023-01-23T18:19:32.693Z      resp = self.client.invoke_binding(value.component_name, value.operation, data, value.metadata)
2023-01-23T18:19:32.693Z    File "/layers/google.python.pip/pip/lib/python3.10/site-packages/dapr/clients/grpc/client.py", line 326, in invoke_binding
2023-01-23T18:19:32.693Z      response, call = self._stub.InvokeBinding.with_call(req, metadata=metadata)
2023-01-23T18:19:32.693Z    File "/layers/google.python.pip/pip/lib/python3.10/site-packages/grpc/_channel.py", line 957, in with_call
2023-01-23T18:19:32.693Z      return _end_unary_response_blocking(state, call, True, None)
2023-01-23T18:19:32.693Z    File "/layers/google.python.pip/pip/lib/python3.10/site-packages/grpc/_channel.py", line 849, in _end_unary_response_blocking
2023-01-23T18:19:32.693Z      raise _InactiveRpcError(state)
2023-01-23T18:19:32.693Z  grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
2023-01-23T18:19:32.693Z  	status = StatusCode.UNAVAILABLE
2023-01-23T18:19:32.693Z  	details = "failed to connect to all addresses; last error: UNKNOWN: Failed to connect to remote host: Connection refused"
2023-01-23T18:19:32.693Z  	debug_error_string = "UNKNOWN:Failed to pick subchannel {created_time:"2023-01-23T18:19:32.688955584+00:00", children:[UNKNOWN:failed to connect to all addresses; last error: UNKNOWN: Failed to connect to remote host: Connection refused {grpc_status:14, created_time:"2023-01-23T18:19:32.688932667+00:00"}]}"

To Reproduce Steps to reproduce the behavior:

  1. Clone the hello-world example into a repository that your cluster can access.
  2. Add git+https://github.com/OpenFunction/functions-framework-python and dapr-ext-grpc to requirements.txt
  3. Modify the yaml specs provided in the README of the hello world example: add an output binding like in the Go example (by the way, the example seems to confuse bindings and pubsub, which leads to an error. I'm using the bindings instead of the pubsub key).
  4. Deploy the function using the modified specs.
  5. Send a POST request to the function.

grigorizaika1 avatar Jan 25 '23 17:01 grigorizaika1

@grigorizaika1 The dapr support to both sync and async python functions is not officially released and supported yet. @kehuili Regarding your PR https://github.com/OpenFunction/functions-framework-python/pull/1 :

  • Is it compatible with the latest OpenFunction v0.8.1 in which we introduce Dapr-Proxy?
  • Is there working samples added for the python sync & async functions dapr integration in https://github.com/OpenFunction/samples/tree/main/functions/async and https://github.com/OpenFunction/samples/tree/main/functions/knative ?

benjaminhuo avatar Jan 28 '23 03:01 benjaminhuo

@grigorizaika1 @benjaminhuo Will look into it.

kehuili avatar Jan 30 '23 02:01 kehuili