0

We are using quart from last 6 months and it was a awesome journey with it. Now we have a new requirement where we need to build a request engine using which we can make request to any url. Now we have tried different url and it work perfectly whereas it fails on the same server request. As it was already running for 3-4 months we can not make a full refactor. is there a better way to handle this scenario?


from quart import Quart, request
import time
import asyncio

import requests

app = Quart(__name__)
 
 
@app.route("/", methods=["POST", "GET"])
async def main_route():
  print("Hello from main route")
  await asyncio.sleep(1)

  loop = asyncio.get_event_loop()

  
  async def handle_future(timeout):
    print("future is here")

    res = requests.get('http://0.0.0.0:5000/test')
    print("Response from test route",res.text)

    await asyncio.sleep(timeout)
    print("I am completed")

  def call_soon():
    asyncio.ensure_future(handle_future(10))

  loop.call_soon_threadsafe(call_soon)

  return "Hello from root"


@app.route("/test", methods=["POST", "GET"])
async def test_route():
  print("Hello from test route")
  await asyncio.sleep(0.5)
  return "Hello from test" + str(time.time())


if __name__ == '__main__':
  from hypercorn.config import Config
  from hypercorn.asyncio import serve

  Config.bind = ["0.0.0.0:5000"]
  asyncio.run(serve(app, Config()))

Output

 * Serving Quart app 'index'
 * Environment: production
 * Please use an ASGI server (e.g. Hypercorn) directly in production
 * Debug mode: False
 * Running on http://0.0.0.0:5000 (CTRL + C to quit)
[2022-03-22 10:54:09,047] Running on http://0.0.0.0:5000 (CTRL + C to quit)
Hello from main route
[2022-03-22 10:54:13,775] 127.0.0.1:49650 GET / 1.1 200 15 1009876
future is here

It was hanged infinitely until the request is timed out. And moreover, it is not accepting any more request during this period

Kundu
  • 3,944
  • 3
  • 16
  • 21
  • NOTE - we have tried Flask and it is not able to run job in background and our entire library and codebase is based on async await. Thus we choose quart. – Kundu Mar 22 '22 at 05:35
  • 1
    The reason you are having trouble with multiple requests is that you’re using a blocking call (i.e., requests.get) to make the requests. Switching to an asyncio-aware library (e.g., aiohttp) will address that. – dirn Mar 22 '22 at 05:47

1 Answers1

2

I'd recommend you use a background task to run a coroutine function in the background (via add_background_task). I'd also recommend you switch from requests to httpx as httpx makes requests without blocking the event loop (you can also use requests by using the app.ensure_async function). This is what I suggest,

import asyncio
import time

import httpx
from quart import Quart, request

app = Quart(__name__)

async def _background_task(timeout):
    async with httpx.AsyncClient() as client:
        response = await client.get('http://0.0.0.0:5000/test')
        print("Response from test route", response.text)
    await asyncio.sleep(timeout)
    print("I am completed")
 
@app.route("/", methods=["POST", "GET"])
async def main_route():
    print("Hello from main route")
    await asyncio.sleep(1)
    app.add_background_task(_background_task, 10)
    return "Hello from root"

@app.route("/test", methods=["POST", "GET"])
async def test_route():
    print("Hello from test route")
    await asyncio.sleep(0.5)
    return "Hello from test" + str(time.time())

if __name__ == '__main__':
    from hypercorn.config import Config
    from hypercorn.asyncio import serve

    Config.bind = ["0.0.0.0:5000"]
    asyncio.run(serve(app, Config()))
pgjones
  • 6,044
  • 1
  • 14
  • 12