Having an asyncio Queue shared between normal sanic code and background task

Hi, I’m new here and would like to ask a question regarding Sanic.

The problem I am facing is that I want to have a producer-consumer design where the consumer is running in the background and producer is running at the http end.

something like:

from sanic import Sanic, response
from asyncio import Queue

app = Sanic(__name__)
q = Queue()


@app.get("/")
async def place_something_on_the_q(request):
    await q.put("item 1")

    return response.json({})


async def consume(app):
    while 1:
        t = await q.get()
        print(t)


app.add_task(consume)

if __name__ == "__main__":
    app.run(host="localhost", port="4000")

The problem is that the background tasks runs in another loop. Is it possible to specify the same loop?

When using app.run(), it will always create a new event loop. Try to use app.create_server() instead of app.run(). See the example.

Another solution would be to use add_task as you started. This is how I would do it: How to use asyncio queues in Sanic?

Thank you both for the responses.

They both work but what is the best?
Is there anything wrong with the following snippet?
Instead of adding a queue to the sanic object I have a global variable.

from sanic import Sanic, response
import asyncio
from signal import signal, SIGINT

app = Sanic(__name__)
q = asyncio.Queue()


@app.get("/")
async def place_something_on_the_q(request):
    await q.put("item 1")

    return response.json({})


async def consume():
    while 1:
        t = await q.get()
        print(t)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    server = app.create_server(host="0.0.0.0", port=4000)
    task = loop.create_task(server)
    task = loop.create_task(consume())
    signal(SIGINT, lambda s, f: loop.stop())
    try:
        loop.run_forever()
    except:
        loop.stop()

No, there is nothing wrong with your strategy. I generally prefer not to have global variables where I can avoid them, and the create_server method may not be as straightforward as app.run. But under the hood they are the same thing.