Python Asyncio Graceful Shutdown (Interrupt Sleep)
December 10, 2020Solution 1: Shutdown Flag
This will enable graceful shutdown, but it will not interrupt ayncio.sleep
(wait until sleep end before shutdown).
import asyncio
import signal
import os
shutdown = False
def stop(signum, frame):
global shutdown
print('STOP', signum)
shutdown = True
print('STOP2')
signal.signal(signal.SIGTERM, stop)
async def run():
while not shutdown:
print('.', end='', flush=True)
await asyncio.sleep(10)
print('run-END')
async def main():
await run()
print('main-END')
if __name__ == '__main__':
print('pid', os.getpid())
asyncio.run(main())
Shutdown
kill [PID]
Solution 2: Task.cancel
- Call Task.cancel to stop asyncio task (will interrupt sleep for immediate shudown)
- Need to use loop.add_signal_handler to listen for signal, else
Task.cancel
would not interrupt sleep immediately - Cons: sleep will raise
asyncio.CancelledError
. If not handled properly, the task might end adruptly.
import asyncio
import signal
import os
import functools
shutdown = False
#def stop(signum, frame):
def stop(signame, loop):
global shutdown
print('STOP', signame)
shutdown = True
# loop = asyncio.get_event_loop()
# loop.close()
tasks = asyncio.all_tasks()
for _task in tasks:
print('cancel task')
_task.cancel()
print('STOP2')
#signal.signal(signal.SIGTERM, stop)
async def run():
while not shutdown:
print('.', end='', flush=True)
try:
await asyncio.sleep(10)
except asyncio.CancelledError as e:
print('run', 'CancelledError', flush=True)
# raise e
print('run-END')
async def main():
loop = asyncio.get_running_loop()
for signame in {'SIGINT', 'SIGTERM'}:
loop.add_signal_handler(
getattr(signal, signame),
functools.partial(stop, signame, loop))
task = asyncio.create_task(run())
try:
await asyncio.gather(task)
except asyncio.CancelledError as e:
print('main', 'cancelledError')
print('main-END')
if __name__ == '__main__':
print('pid', os.getpid())
asyncio.run(main())
Solution 3: Interrupt Sleep
- We create a special sleep function which are cancellable tasks.
- Pros:
- Don’t have to handle
asyncio.CancelledError
for every sleep call. Asyncio.Task
won’t end adruptly.
- Don’t have to handle
class Sleep:
def __init__(self):
self.tasks = set()
async def sleep(self, delay, result=None):
task = asyncio.create_task(asyncio.sleep(delay, result))
self.tasks.add(task)
try:
return await task
except asyncio.CancelledError:
return result
finally:
self.tasks.remove(task)
def cancel_all(self):
for _task in self.tasks:
_task.cancel()
# self.tasks = set()
light = Sleep()
def stop(signame, loop):
global shutdown
print('STOP', signame)
shutdown = True
light.cancel_all()
print('STOP2')
async def run():
while not shutdown:
print('.', end='', flush=True)
# wait asyncio.sleep(10)
await light.sleep(10)
print('run-END')
async def main():
loop = asyncio.get_running_loop()
for signame in {'SIGINT', 'SIGTERM'}:
loop.add_signal_handler(
getattr(signal, signame),
functools.partial(stop, signame, loop))
task = asyncio.create_task(run())
await asyncio.gather(task)
print('main-END')
if __name__ == '__main__':
print('pid', os.getpid())
asyncio.run(main())
❤️ Is this article helpful?
Buy me a coffee☕ or support my work to keep this space 🖖 and ad-free.
If you can't, do send some 💖 to @d_luaz or help to share this article.
If you can't, do send some 💖 to @d_luaz or help to share this article.
👶 Apps I built
Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.Pixtory App (Alpha) - easily organize photos on your phone into a blog.
暖心芽 (WIP) 🌞❤️🌱 - reminder of hope, warmth, thoughts and feelings (or just quotes).
LuaPass - offline password manager
By Desmond Lua
- algo-trading
- algolia
- analytics
- android
- android-ktx
- android-permission
- android-studio
- apps-script
- bash
- binance
- bootstrap
- bootstrapvue
- chartjs
- chrome
- cloud-functions
- coding-interview
- contentresolver
- coroutines
- crashlytics
- crypto
- css
- dagger2
- datastore
- datetime
- docker
- eslint
- firebase
- firebase-auth
- firebase-hosting
- firestore
- firestore-security-rules
- flask
- fontawesome
- fresco
- git
- github
- glide
- godot
- google-app-engine
- google-cloud-storage
- google-colab
- google-drive
- google-maps
- google-places
- google-play
- google-sheets
- gradle
- html
- hugo
- inkscape
- java
- java-time
- javascript
- jetpack-compose
- jetson-nano
- kotlin
- kotlin-serialization
- layout
- lets-encrypt
- lifecycle
- linux
- logging
- lubuntu
- markdown
- mate
- material-design
- matplotlib
- md5
- mongodb
- moshi
- mplfinance
- mysql
- navigation
- nginx
- nodejs
- npm
- nuxtjs
- nvm
- pandas
- payment
- pip
- pwa
- pyenv
- python
- recylerview
- regex
- room
- rxjava
- scoped-storage
- selenium
- social-media
- ssh
- ssl
- static-site-generator
- static-website-hosting
- sublime-text
- ubuntu
- unit-test
- uwsgi
- viewmodel
- viewpager2
- virtualbox
- vue-chartjs
- vue-cli
- vue-router
- vuejs
- vuelidate
- vuepress
- web-development
- web-hosting
- webpack
- windows
- workmanager
- wsl
- yarn