sabuhish / fastapi-mqtt

fastapi-mqtt is extension for MQTT protocol
https://sabuhish.github.io/fastapi-mqtt/
MIT License
256 stars 43 forks source link

Error run fastapi-mqtt using gunicorn #25

Closed ruem2802 closed 9 months ago

ruem2802 commented 2 years ago

I use fastapi-mqtt==0.3.0, python==3.9.7, fastapi==0.68.1 I run example application by command : uvicorn app:app --host 0.0.0.0 --port 7000 --reload Everything is ok -> app run

But: I run example application by command : gunicorn app:app -k uvicorn.workers.UvicornWorker --workers=9 -b 0.0.0.0:7000

Error : File "/home/hoanganh/smarthome-server/venv/lib/python3.9/site-packages/gmqtt/client.py", line 230, in connect await self._connected.wait() File "/usr/lib/python3.9/asyncio/locks.py", line 226, in wait await fut RuntimeError: Task <Task pending name='Task-3' coro=<LifespanOn.main() running at /home/hoanganh/smarthome-server/venv/lib/python3.9/site-packages/uvicorn/lifespan/on.py:84>> got Future attached to a different loop

[2021-09-21 20:42:13 +0700] [10419] [ERROR] Application startup failed. Exiting. [2021-09-21 20:42:13 +0700] [10419] [INFO] Worker exiting (pid: 10419) Task was destroyed but it is pending! task: <Task pending name='Task-1' coro=<Client._resend_qos_messages() running at /home/hoanganh/smarthome-server/venv/lib/python3.9/site-packages/gmqtt/client.py:176>> sys:1: RuntimeWarning: coroutine 'Client._resend_qos_messages' was never awaited [2021-09-21 20:42:14 +0700] [10418] [INFO] Shutting down: Master [2021-09-21 20:42:14 +0700] [10418] [INFO] Reason: Worker failed to boot.

sabuhish commented 2 years ago

Hi, I gave a simple solution here can you check this pls and let me know.

https://github.com/sabuhish/fastapi-mqtt/issues/17

ruem2802 commented 2 years ago

Hi, I gave a simple solution here can you check this pls and let me know.

17

I try and error!

DavidOsparks commented 1 year ago

I had the same problem. Simple uvicorn running was working well, but

gunicorn --workers=2 -k uvicorn.workers.UvicornWorker my_api:app

or even use tiangolo/uvicorn-gunicorn-fastapi:python3.8 to run my program got the same error:

[2023-01-04 17:28:07 +0800] [9531] [ERROR] Traceback (most recent call last):
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/starlette/routing.py", line 540, in lifespan
    async for item in self.lifespan_context(app):
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/starlette/routing.py", line 481, in default_lifespan
    await self.startup()
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/starlette/routing.py", line 516, in startup
    await handler()
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/fastapi_mqtt/fastmqtt.py", line 232, in startup
    await self.connection()
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/fastapi_mqtt/fastmqtt.py", line 130, in connection
    await self.client.connect(
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/gmqtt/client.py", line 230, in connect
    await self._connected.wait()
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/asyncio/locks.py", line 309, in wait
    await fut
RuntimeError: Task <Task pending name='Task-3' coro=<LifespanOn.main() running at /opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/uvicorn/lifespan/on.py:86>> got Future <Future pending> attached to a different loop

[2023-01-04 17:28:07 +0800] [9531] [ERROR] Application startup failed. Exiting.
[2023-01-04 17:28:07 +0800] [9531] [INFO] Worker exiting (pid: 9531)
[2023-01-04 17:28:07 +0800] [9530] [ERROR] Traceback (most recent call last):
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/starlette/routing.py", line 540, in lifespan
    async for item in self.lifespan_context(app):
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/starlette/routing.py", line 481, in default_lifespan
    await self.startup()
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/starlette/routing.py", line 516, in startup
    await handler()
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/fastapi_mqtt/fastmqtt.py", line 232, in startup
    await self.connection()
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/fastapi_mqtt/fastmqtt.py", line 130, in connection
    await self.client.connect(
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/gmqtt/client.py", line 230, in connect
    await self._connected.wait()
  File "/opt/anaconda3/envs/vpin_venv/lib/python3.8/asyncio/locks.py", line 309, in wait
    await fut
RuntimeError: Task <Task pending name='Task-3' coro=<LifespanOn.main() running at /opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/uvicorn/lifespan/on.py:86>> got Future <Future pending> attached to a different loop

[2023-01-04 17:28:07 +0800] [9530] [ERROR] Application startup failed. Exiting.
[2023-01-04 17:28:07 +0800] [9530] [INFO] Worker exiting (pid: 9530)
Task was destroyed but it is pending!
task: <Task pending name='Task-1' coro=<Client._resend_qos_messages() running at /opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/gmqtt/client.py:176>>
sys:1: RuntimeWarning: coroutine 'Client._resend_qos_messages' was never awaited
Task was destroyed but it is pending!
task: <Task pending name='Task-1' coro=<Client._resend_qos_messages() running at /opt/anaconda3/envs/vpin_venv/lib/python3.8/site-packages/gmqtt/client.py:176>>
sys:1: RuntimeWarning: coroutine 'Client._resend_qos_messages' was never awaited
[2023-01-04 17:28:07 +0800] [9528] [WARNING] Worker with pid 9530 was terminated due to signal 15
[2023-01-04 17:28:07 +0800] [9528] [INFO] Shutting down: Master
[2023-01-04 17:28:07 +0800] [9528] [INFO] Reason: Worker failed to boot.
tomliptrot commented 1 year ago

Was there any further thoughts on this? The error is mentioned here https://github.com/tiangolo/fastapi/issues/3939.

This response suggest a solution https://github.com/tiangolo/fastapi/issues/3939#issuecomment-926473100

This is both gmqtt and fastapi-mqtt fault. It's the same issue we have with motor.

Step by step:

The example initializes FastMQTT. On FastMQTT, they initialize the MQTTClient. MQTTClient is a class that inherits some other classes on the gmqtt project, and one of those classes is EventCallback. EventCallback runs asyncio.Event(). asyncio.Event() tries to get the current event loop internally and then the event is created on this event loop. gunicorn runs and uvicorn creates its own event loop. MQTTClient runs await self._connected.wait() at some point, and this operation runs on a different loop than the one uvicorn created. In any case, possible solutions:

Add FastMQTT initialization on a startup event. Ask for the fastapi-mqtt maintainer to change the place where 2 is done (it should be on their startup event).

vvanglro commented 1 year ago

Hope that solves this problem. 🥳

azogue commented 9 months ago

Closing this one as completed. In recent versions there is support for lifespan async context manager, and the init_app legacy method also works.

The example apps work with both uvicorn and gunicorn

goldyfruit commented 2 weeks ago

Using lifespan doesn't fix the issue in my case as if I set unicorn with --workers to 4 then I got one session per thread which is not allowed by VerneMQ (related issue https://github.com/vernemq/vernemq/issues/2346).

Is there a way to only open one connection when running will multiple workers?

azogue commented 2 weeks ago

Is there a way to only open one connection when running will multiple workers?

No, sorry. The library is intended to work only in mono-process/thread environments