I have a async web service (with FastAPI) that runs a sync background task.
The idea begin the code is:
The FastAPI async code receives a task request.
This request has an Event flag
It adds the request to a Priority Queue and then waits until the Event of the task is set or a timeout is reached.
A sync background thread worker finishes all tasks in the queue and sets the event.
How can I pass the Event in a way that the async code can reliably wait for it?
Code example:
import asyncio
from fastapi import FastAPI
import time
import uvicorn
from random import randint
from threading import Thread
import asyncio
from asyncio.locks import Event
from queue import PriorityQueue, Empty
global_pq = PriorityQueue()
global_task_count = 0
def background_thread():
while True:
time.sleep(0.5)
try:
task: MyTask
task = global_pq.get(block=None)
print(f'background {time.time()} {task}')
task.complete()
except Empty:
print(f'background {time.time()} {None}')
bg = Thread(target=background_thread)
bg.setDaemon(True)
bg.start()
class MyTask:
def __init__(self, no):
self.event = Event()
self.priority = randint(1, 5)
self.no = no
def __lt__(self, other):
return self.priority < other.priority
def __repr__(self):
return f'Task No {self.no}, Priority {self.priority}'
def complete(self):
self.event._loop.call_soon_threadsafe(self.event.set)
# self.event.set(True)
app = FastAPI()
@app.get("/")
async def root():
global global_task_count
global_task_count += 1
mytask = MyTask(no=global_task_count)
global_pq.put((mytask.priority, mytask))
with asyncio.wait_for(mytask.event.wait(), timeout=5.0):
pass
return {"count": global_task_count}
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0', port=9000)