What is the best approach of "Fire and forget" in such case ? I am aware that non awaited tasks will be garbage collected,
That is not true: non-awaited tasks created by asyncio.create_task()
will not be garbage collected so long as they run. They are owned by the event loop and will run to completion (or never complete, if they are written to run forever) regardless of whether they're being explicitly awaited.
For example, this code creates two "background" tasks without awaiting them, and proceeds to do something else.
async def counter(msg, delay):
i = 0
while True:
print(msg, i)
i += 1
await asyncio.sleep(delay)
async def main():
# create two task
asyncio.create_task(counter('slow', 1))
asyncio.create_task(counter('fast', .3))
# ...and wait forever
await asyncio.Event().wait()
asyncio.run(main())
that's the reason I find myself forced to await forever running tasks.
It's certainly a good idea to await background tasks when possible, so that you collect their results or receive the exceptions they raise, but it's by no means a requirement. Some tasks don't have a meaningful return value, and it's ok to leave them running on their own.