简体   繁体   中英

Why am I getting “RuntimeError: This event loop is already running”

Im working on a slack bot using the new slack 2.0 python library. I am new to python decorators and I suspect that is part of my problem.

Here is my code...

#!/opt/rh/rh-python36/root/usr/bin/python
import os
import slack

# instantiate Slack client
slack_token = os.environ['SLACK_BOT_TOKEN']
rtmclient = slack.RTMClient(token=slack_token)
webclient = slack.WebClient(token=slack_token)

# get the id of my user
bot_id = webclient.auth_test()['user_id']
print('Bot ID: {0}'.format(bot_id))

def get_user_info(user_id):
    user_info = webclient.users_info(user=user_id)['ok']
    return user_info

@slack.RTMClient.run_on(event='message')
def parse_message(**payload):
    data = payload['data']
    user_id = data['user']
    print(get_user_info(user_id))

rtmclient.start()

It outputs the Bot ID(using the webclient ) when started but then crashes with RuntimeError: This event loop is already running when I make another call to webclient .

[root@slackbot-01 bin]# scl enable rh-python36 /root/slackbot/bin/slackbot.py
Bot ID: UBT547D31
Traceback (most recent call last):
  File "/root/slackbot/bin/slackbot.py", line 24, in <module>
    rtmclient.start()
  File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 197, in start
    return self._event_loop.run_until_complete(future)
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/asyncio/base_events.py", line 467, in run_until_complete
    return future.result()
  File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 339, in _connect_and_read
    await self._read_messages()
  File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 390, in _read_messages
    await self._dispatch_event(event, data=payload)
  File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 440, in _dispatch_event
    self._execute_in_thread(callback, data)
  File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/rtm/client.py", line 465, in _execute_in_thread
    future.result()
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/concurrent/futures/_base.py", line 425, in result
    return self.__get_result()
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/concurrent/futures/_base.py", line 384, in __get_result
    raise self._exception
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/root/slackbot/bin/slackbot.py", line 22, in parse_message
    print(get_user_info(user_id))
  File "/root/slackbot/bin/slackbot.py", line 15, in get_user_info
    user_info = webclient.users_info(user=user_id)
  File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/web/client.py", line 1368, in users_info
    return self.api_call("users.info", http_verb="GET", params=kwargs)
  File "/opt/rh/rh-python36/root/usr/lib/python3.6/site-packages/slack/web/base_client.py", line 154, in api_call
    return self._event_loop.run_until_complete(future)
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/asyncio/base_events.py", line 454, in run_until_complete
    self.run_forever()
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/asyncio/base_events.py", line 408, in run_forever
    raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running

The really confusing part to me is that if I comment out the line that makes the first call to webclient.auth_test() , I have no issues at all. My call to webclient.users_info() works every time rtmclient sends me data.

#!/opt/rh/rh-python36/root/usr/bin/python
import os
import slack

# instantiate Slack client
slack_token = os.environ['SLACK_BOT_TOKEN']
rtmclient = slack.RTMClient(token=slack_token)
webclient = slack.WebClient(token=slack_token)

# get the id of my user
#bot_id = webclient.auth_test()['user_id']
#print('Bot ID: {0}'.format(bot_id))

def get_user_info(user_id):
    user_info = webclient.users_info(user=user_id)['ok']
    return user_info

@slack.RTMClient.run_on(event='message')
def parse_message(**payload):
    data = payload['data']
    user_id = data['user']
    print(get_user_info(user_id))

rtmclient.start()
[root@slackbot-01 bin]# scl enable rh-python36 /root/slackbot/bin/slackbot.py
True
True
^C[root@slackbot-01 bin]#

I need to get the bot id so that I can make sure it doesnt answer it's own messages. I don't why my code doesnt work after I get the bot id outside of the parse message function with a decorator.

What am I doing wrong here?

The python event loop is a tricky thing to program libraries around and there are some issues with the way the event queue is managed in the 2.0 version of SlackClient. It looks like some improvements were made with 2.1 but it appears to be a work in progress, and I still encounter this. I'd expect there will be future updates to make it more robust.

In the meantime, the following code at the top of your file (use pip to install) usually resolves it for me:

import nest_asyncio
nest_asyncio.apply()

Keep in mind this will alter the way the rest of your application is handling the event queue, if that's a factor.

If you're using RTM, the RTMClient creates a WebClient for you. The handle for it should be getting passed to you in the payload when you handle an event. You can check your ID by looking for the 'open' event which is always dispatched after RTM successfully connects and doing the lookup inside your 'open' event handler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM