개요
2025.01.09-[Python] signal - 프로그램 종료 처리에서 Python 프로그램의 프로그램 종료 등의 처리를 위한 signal 모듈 사용방법에 대해 알아보았다. 그런데 이제는 비동기로 프로그래밍된 Python 프로그램의 종료 시에 처리해야 할 작업이 생겼다. 이번 글에서는 Python async를 사용할 때에 signal 수신 및 처리 방법을 알아보자.
loop.add_signal_handler
Python은 asyncio라는 고수준 라이브러리로 비동기 프로그래밍을 쉽게 할 수 있지만, signal 처리와 같은 세부 제어를 하기 위해서는 이벤트 루프를 직접 다루어야 한다.
이벤트 루프는 시그널 처리를 위한 add_signal_handler라는 함수를 제공한다.
loop.add_signal_handler(signum, callback, *args)
add_signal_handler 함수는 callback을 signum의 처리기로 설정한다. signal.signal로 등록된 handler와 다르게, add_signal_handler로 등록한 handler는 이벤트 루프와 상호작용할 수 있다.
만약 callabck 함수에 매개변수가 존재하면 *args로 전달하거나, functools.partial을 사용하여 callable로 전달한다.
예시
예시로 아래와 같이 비동기로 동작하는 프로그램이 있다고 하자. 실행 시 '프로그램 시작'이라는 문자열을 출력하고 그대로 대기만 하는 프로그램이다.
import asyncio
async def main():
print('프로그램 시작')
await asyncio.Event().wait()
if __name__ == "__main__":
asyncio.run(main())
이제 이 프로그램이 키보드 입력에 의한 종료 시그널을 받으면 '프로그램 종료'라는 문자열을 출력하고 프로그램을 종료하게끔 하고 싶다.
이를 위해 시그널을 받았을 때 호출할 handler를 먼저 정의하고, 이벤트 루프에 시그널과 handler를 등록한다.
import signal
def shutdown_handler():
print('프로그램 종료')
exit()
async def main():
# 이벤트 루프 얻음
loop = asyncio.get_event_loop()
# 시그널 핸들러 등록
loop.add_signal_handler(signal.SIGINT, shutdown_handler)
print('프로그램 시작')
await asyncio.Event().wait()
의도한 대로 ctrl + c를 입력받으면 '프로그램 종료'라는 문자열을 출력하면서 프로그램이 종료되는 모습을 확인할 수 있다.
참고 문서
https://docs.python.org/ko/3.10/library/asyncio-eventloop.html
https://tech.buzzvil.com/blog/asyncio-no-3-sigterm/
https://tot0rokr.github.io/python/python-asyncio-graceful-shutdown/