Vaelor / python-mattermost-driver

Python Mattermost Driver for APIv4
https://vaelor.github.io/python-mattermost-driver/
MIT License
189 stars 69 forks source link

Driver.disconnect can't end the event_loop gracefully when running in a thread #113

Open Martzki opened 2 years ago

Martzki commented 2 years ago

Here is my code:

from mattermostdriver import Driver
import threading
import asyncio
import time
import logging

logging.basicConfig(level=logging.DEBUG)

async def h(a):
    print('a')

def w():
    asyncio.set_event_loop(asyncio.new_event_loop())
    d.init_websocket(h)

d = Driver( options={
            'url'    : '172.17.0.1',
            'scheme' : 'http',
            'port'   : 8065,
            'login_id'   : 'aaa', # use the new Authenticator class defined above
            'password': 'aaaaa'
        } )

d.login()

t = threading.Thread(target=w)
t.start()

try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    d.disconnect()
    # t.join()

I am running the Driver.init_websocket() in another thread w. When I'm calling the Driver.disconnect(), the event_loop keep running and finally we got error ERROR:asyncio:Task was destroyed but it is pending! like this:

INFO:mattermostdriver.websocket:Websocket authentification OK
a
DEBUG:websockets.protocol:client - event = data_received(<204 bytes>)
DEBUG:websockets.protocol:client < Frame(fin=True, opcode=<Opcode.TEXT: 1>, data=b'{"event":"status_change","data":{"status":"online","user_id":"qwmdq4yroffqf8xufok94w7xdc"},"broadcast":{"omit_users":null,"user_id":"qwmdq4yroffqf8xufok94w7xdc","channel_id":"","team_id":""},"seq":1}\n', rsv1=False, rsv2=False, rsv3=False)
a
^CINFO:mattermostdriver.websocket:Disconnecting websocket
DEBUG:websockets.protocol:client > Frame(fin=True, opcode=<Opcode.PING: 9>, data=b'sr`k', rsv1=False, rsv2=False, rsv3=False)
DEBUG:websockets.protocol:client - event = data_received(<6 bytes>)
DEBUG:websockets.protocol:client < Frame(fin=True, opcode=<Opcode.PONG: 10>, data=b'sr`k', rsv1=False, rsv2=False, rsv3=False)
DEBUG:websockets.protocol:client - received solicited pong: 7372606b
DEBUG:websockets.protocol:client > Frame(fin=True, opcode=<Opcode.PONG: 10>, data=b'', rsv1=False, rsv2=False, rsv3=False)
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending coro=<WebSocketCommonProtocol.transfer_data() done, defined at /usr/local/lib64/python3.6/site-packages/websockets/legacy/protocol.py:741> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f403c3b2528>()]> cb=[<TaskWakeupMethWrapper object at 0x7f403c3b24c8>(), _wait.<locals>._on_completion() at /usr/lib64/python3.6/asyncio/tasks.py:380]>
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending coro=<WebSocketCommonProtocol.keepalive_ping() done, defined at /usr/local/lib64/python3.6/site-packages/websockets/legacy/protocol.py:1027> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f403c3b2468>()]>>
DEBUG:websockets.protocol:client x closing TCP connection
Exception ignored in: <coroutine object WebSocketCommonProtocol.close_connection at 0x7f403c35d1a8>
Traceback (most recent call last):
  File "/usr/local/lib64/python3.6/site-packages/websockets/legacy/protocol.py", line 1134, in close_connection
    self.transport.close()
  File "/usr/lib64/python3.6/asyncio/selector_events.py", line 610, in close
    self._loop.call_soon(self._call_connection_lost, None)
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 591, in call_soon
    self._check_closed()
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 377, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending coro=<WebSocketCommonProtocol.close_connection() done, defined at /usr/local/lib64/python3.6/site-packages/websockets/legacy/protocol.py:1079> wait_for=<Task pending coro=<WebSocketCommonProtocol.transfer_data() done, defined at /usr/local/lib64/python3.6/site-packages/websockets/legacy/protocol.py:741> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f403c3b2528>()]> cb=[<TaskWakeupMethWrapper object at 0x7f403c3b24c8>(), _wait.<locals>._on_completion() at /usr/lib64/python3.6/asyncio/tasks.py:380]>>

I'm not good at python so I'm not sure if it's an issue.

Martzki commented 2 years ago

That's werid. Seems I shouldn't create a new event_loop in a thread. When I do this, the errors are gone:

diff --git a/11.py b/1.py
index 16145fe..a1e117f 100644
--- a/11.py
+++ b/1.py
@@ -9,8 +9,8 @@ logging.basicConfig(level=logging.DEBUG)
 async def h(a):
        print('a')

-def w():
-       asyncio.set_event_loop(asyncio.new_event_loop())
+def w(loop):
+       asyncio.set_event_loop(loop)
        d.init_websocket(h)

 d = Driver( options={
@@ -23,7 +23,7 @@ d = Driver( options={

 d.login()

-t = threading.Thread(target=w)
+t = threading.Thread(target=w, args=[asyncio.get_event_loop()])
 t.start()

 try:
Martzki commented 2 years ago

I got

To handle signals and to execute subprocesses, the event loop must be run in the main thread.

from event_loop doc so I'll try to use multiprocessing instead :)