ERROR:root:Error in xyz There is no current event loop in thread 'Thread-7'

222 Views Asked by At

I am trying to achieve fire_and_forget functionality and here are the details.

Async decorater i am trying to use:

import asyncio
import time


def fire_and_forget(f):
    def wrapped(*args, **kwargs):
        return asyncio.get_event_loop().run_in_executor(None, f, *args, *kwargs)

    return wrapped

My Async call using above decorator:

@fire_and_forget
def call_async(self, req, body, headers_params):
    logger.info("Calling ASYNC")
    try:
        f = urllib.request.urlopen(req)
        response = f.read()
        f.close()
    except Exception as e:
        logger.exception("api exception %s" % e)
        return None

    # Parse and return the response
    try:
        res = self._parse_response(response)
    except Exception as e:
        logger.exception("Exception in parsing response of %s" % e)
        res = None
    logger.debug("clevertap response: {}".format(res))
    

My Flask app calling test_xyz which in turns fire the above fire and forget call_async:

from flask import Flask, jsonify, request
from call_xyz import test_xyz

app = Flask(__name__)

@app.route('/events_dm')
def events_dm():
    session_id = request.args.get('sessionId', "11111111")
    test_obj = test_xyz(session_id)
    test_obj.track_test()
    return jsonify({"success": True})


app.run(
            host='0.0.0.0',
            port=8091,
            debug=True,
            threaded=True
        )

I am not able to understand where to set my event loop correctly so that i don't get the error: "Error in xyz There is no current event loop in thread 'Thread-7'" and my events get fired correctly.

2

There are 2 best solutions below

0
On

Flask is not asyncio-compatible, so you shouldn't attempt to use asyncio within it.

Besides, you're not actually using asyncio's functionality, but run_in_executor which calls into concurrent.futures, i.e. uses threads under the hood. If that's what you need, you can create an executor directly and just submit your function to it. For example:

import concurrent.futures
_pool = concurrent.futures.ThreadPoolExecutor()

def fire_and_forget(f):
    def wrapped(*args, **kwargs):
        return _pool.submit(lambda: f(*args, **kwargs))
    return wrapped
0
On

You must probably go through once asyncio usage and its main heart event loop understanding.

Similar issue which might help you to understand.

Here is the tutorial with some good explanation

Just give some flow for how use coroutine with normal Flask app here is the sample one.

import asyncio
import datetime

from flask import Flask, jsonify, request


app = Flask(__name__)

def print_now():
    print(datetime.datetime.now())


async def keep_printing(name: str="") -> None:
    print(name, end=" ")
    print_now()
    await asyncio.sleep(1.50)


async def main(num_times):
    result = await asyncio.gather(
        keep_printing("first"),
        keep_printing("second"),
        keep_printing("third"),
    )
    return result


def execute_statement():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(main(2))
    loop.close()


@app.route('/events_dm')
def events_dm():
    execute_statement()
    return jsonify({"success": True})

app.run(
            host='0.0.0.0',
            port=8091,
            debug=True,
            threaded=True
        )

Output when you hit /events_dm

first 2020-07-18 00:46:26.452921
second 2020-07-18 00:46:26.452921
third 2020-07-18 00:46:26.452921
127.0.0.1 - - [18/Jul/2020 00:46:27] "GET /events_dm HTTP/1.1" 200 -