You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have an app that has background task, and this background task needs some time to finish once shutdown (initiated by SIGINT) is requested. Unfortunately, this seldom works as expected - often it never finishes and gets stuck in shutdown_tasks().
The are couple problems that I recognize but could not find a solution yet. The part of the code that is handling shutdown:
by default increment = 0.1, eventually it becomes negative due to imprecise nature of floats, thus loop will never finish as long as there are running tasks. Actually there is no "safe" value for an increment as long as either timeout or increment are not integers.
there is always running (background) task as asyncio loop is killed at this point and the while loop is in eternal cycle (and get_running_loop() produces an exception), so it eats 100% CPU as well.
Since background_task() is perfectly terminates by SIGINT when run directly using asyncio.run(background_task()) (after cancellation), I believe the problem is in Sanic.
The following snippet could be used to reproduce the problem (I ran it on Debian 12, Python 3.11):
Code snippet
importasyncioimportsignalfromsanicimportSanicapp=Sanic("sanic-bug")
app.config.GRACEFUL_SHUTDOWN_TIMEOUT=5bg_task: asyncio.Task|None=Noneasyncdefbackground_task():
print("Background task running")
try:
print("Sleep one")
awaitasyncio.sleep(30)
exceptasyncio.CancelledError:
# This get executed when Ctrl-C is hit as task is cancelledprint("Sleep one cancelled")
try:
print(f"Sleep two {asyncio.get_running_loop()}")
# This never finishes as long as timeout is > 0# and Sanic.shutdown_tasks() is in eternal loop,awaitasyncio.sleep(5)
exceptasyncio.CancelledError:
print("Sleep two cancelled")
asyncio.current_task().uncancel()
exceptBaseExceptionase:
print(f"Oops: {e!r}")
print("Background task finished")
return@app.before_server_startasyncdefprepare_start(*args):
print("Starting background task")
_=app.add_task(background_task(), name="background-task", register=True)
print("Started background task")
if__name__=="__main__":
app.run(host="0.0.0.0", single_process=True)
The output:
Starting background task
Started background task
Background task running
Sleep one
[2024-01-19 13:48:59 +0100] [857208] [INFO] Starting worker [857208]
^CSleep one cancelled
Sleep two <uvloop.Loop running=True closed=False debug=False>
[2024-01-19 13:49:02 +0100] [857208] [INFO] Stopping worker [857208]
At this point it hangs forever. This also affect multi-process mode.
Expected Behavior
I would expect that asyncio loop is not touched until and unless all background tasks are finished or when GRACEFUL_SHUTDOWN_TIMEOUT expires, in the latter case it could be forcibly killed.
How do you run Sanic?
As a script (app.run or Sanic.serve)
Operating System
Linux
Sanic Version
23.12.1
Additional context
No response
The text was updated successfully, but these errors were encountered:
Is there an existing issue for this?
Describe the bug
I have an app that has background task, and this background task needs some time to finish once shutdown (initiated by
SIGINT
) is requested. Unfortunately, this seldom works as expected - often it never finishes and gets stuck inshutdown_tasks()
.The are couple problems that I recognize but could not find a solution yet. The part of the code that is handling shutdown:
sanic/sanic/app.py
Lines 1910 to 1918 in acb29c9
increment = 0.1
, eventually it becomes negative due to imprecise nature of floats, thus loop will never finish as long as there are running tasks. Actually there is no "safe" value for anincrement
as long as eithertimeout
orincrement
are not integers.get_running_loop()
produces an exception), so it eats 100% CPU as well.Since
background_task()
is perfectly terminates bySIGINT
when run directly usingasyncio.run(background_task())
(after cancellation), I believe the problem is inSanic
.The following snippet could be used to reproduce the problem (I ran it on Debian 12, Python 3.11):
Code snippet
The output:
At this point it hangs forever. This also affect multi-process mode.
Expected Behavior
I would expect that asyncio loop is not touched until and unless all background tasks are finished or when
GRACEFUL_SHUTDOWN_TIMEOUT
expires, in the latter case it could be forcibly killed.How do you run Sanic?
As a script (
app.run
orSanic.serve
)Operating System
Linux
Sanic Version
23.12.1
Additional context
No response
The text was updated successfully, but these errors were encountered: