errbotio / errbot

Errbot is a chatbot, a daemon that connects to your favorite chat service and bring your tools and some fun into the conversation.
http://errbot.io
GNU General Public License v3.0
3.12k stars 614 forks source link

asyncio error on self.send() #1532

Closed m00lean closed 8 months ago

m00lean commented 3 years ago

I am...

I am running...

Issue description

I've got a very simple webhook plugin that should send a message to a room (XMPP backend) like this:

    @webhook(raw=True)
    def room(self, request):
        data = request.get_json()
        self.send(
            self.build_identifier(data['room']), data['msg'],
        )

Everytime the plugin would send a message, I run into an error with a missing async loop:

02:26:59 ERROR    errbot.core_plugins       Exception on /room [POST]
Traceback (most recent call last):
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/flask/app.py", line 2070, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/flask/app.py", line 1515, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/flask/app.py", line 1513, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/flask/app.py", line 1499, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/flask/views.py", line 83, in view
    return self.dispatch_request(*args, **kwargs)
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/errbot/core_plugins/wsview.py", line 77, in dispatch_request
    response = self.func(request, **kwargs)
  File "data/plugins/webhook/webhook.py", line 8, in room
    self.build_identifier(data['room']), data['msg'],
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/errbot/botplugin.py", line 714, in build_identifier
    return self._bot.build_identifier(txtrep)
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/errbot/backends/xmpp.py", line 604, in build_identifier
    info = xep0030.get_info(jid=txtrep)
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/slixmpp/xmlstream/asyncio.py", line 15, in wrapper
    result = func(*args, **kwargs)
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/slixmpp/plugins/xep_0030/disco.py", line 396, in get_info
    return iq.send(timeout=kwargs.get('timeout', None),
  File "/home/m00lean/.errbot-ve/lib/python3.9/site-packages/slixmpp/stanza/iq.py", line 188, in send
    future = asyncio.Future()
  File "/usr/lib/python3.9/asyncio/futures.py", line 79, in __init__
    self._loop = events.get_event_loop()
  File "/usr/lib/python3.9/asyncio/events.py", line 642, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-17'.

Steps to reproduce

See above.

ariep commented 2 years ago

I have had this error before when using slixmpp, I think it's this issue.

A workaround for that issue is to add a piece of code to your plugin function, before it starts calling (xmpp) message functions:

import asyncio
try:
    asyncio.get_event_loop()
except RuntimeError:
    # slixmpp can not handle not having an event_loop
    # see: https://lab.louiz.org/poezio/slixmpp/-/issues/3456
    asyncio.set_event_loop(asyncio.new_event_loop())

However, after applying this fix, I get another error:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/usr/local/lib/python3.9/site-packages/flask/views.py", line 84, in view
    return current_app.ensure_sync(self.dispatch_request)(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/errbot/core_plugins/wsview.py", line 98, in dispatch_request
    response = self.func(data, **kwargs)
  File "/plugins/Notify/notify.py", line 15, in notify
    self.build_identifier("REMOVED"),
  File "/usr/local/lib/python3.9/site-packages/errbot/botplugin.py", line 716, in build_identifier
    return self._bot.build_identifier(txtrep)
  File "/usr/local/lib/python3.9/site-packages/errbot/backends/xmpp.py", line 615, in build_identifier
    disco_info = info["disco_info"]
TypeError: '_asyncio.Future' object is not subscriptable

Maybe errbot has not adapted to recent changes in the slixmpp interface, in particular its asyncio nature? Just guessing here.

sijis commented 2 years ago

Errbot is not setup to use asyncio. It's all threaded.

ariep commented 2 years ago

Errbot is not setup to use asyncio. It's all threaded.

Right. However slixmpp does use asyncio, and apparently we can't completely avoid using it -- at least the documented way to send a message to a specific recipient -- hich is also the way to send a message at all from a webhook IIUC -- fails to work with the xmpp backend because of this.

I'll try to encapsulate the asyncio functions where errbot calls them, but my first attempt at that failed: the process calling the webhook hangs because it never receives a response from errbot. I hope to debug that further later when I have time again to work on this.