[문제] subprocess.TimeoutExpired 에러가 발생한 경우, subprocess.run() 에서는 child process를 삭제할 수 없음
[해결] subprocess.Popen()으로 converting 했다.
방법 1. proc.kill()로 프로세스 종료
https://docs.python.org/3.9/library/subprocess.html
The child process is not killed if the timeout expires, so in order to cleanup properly a well-behaved application should kill the child process and finish communication:
proc = subprocess.Popen(cmd, ...)
try:
outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
print('timeout expired')
proc.kill()
outs, errs = proc.communicate()
그런데 어떤 경우에는 TimeoutExpired에서 proc.kill()을 해도 proc.communicate() 으로 넘어가지 않고 그대로 물려있다.
+추가) proc.terminate() -> proc.kill() 시 원하는대로 프로세스 종료되고 proc.communicate() 실행됨
방법 2. os.killpg(os.getpgid(proc.pid), signal.SIGTERM) 로 프로세스 종료
참고 https://alexandra-zaharia.github.io/posts/kill-subprocess-and-its-children-on-timeout-python/
import os
import signal
import subprocess
try:
proc = subprocess.Popen(cmd, ..., start_new_session=True)
outs, errs = proc.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
print('timeout expired!!!')
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
outs, errs = proc.communicate()
이 경우에는 TimeoutExpired에서 프로세스 signal.SIGTERM 후에 proc.communicate() 으로 넘어가고 다음으로 진행되었다.
+ 추가)
위 코드를 통해 child process를 종료한 뒤, ps -ef로 확인했을 때 아래와 같이 <defunct> (좀비프로세스)가 남는 경우가 있었으나, 해당 프로세스의 ppid를 kill 하지 않아도 문제 없이 넘어갔다.
* how to get ppid? --> ppid = psutil.Process(os.getpgid(proc.pid)).ppid())
UID PID PPID C STIME TTY TIME CMD
jenkins 1550 1464 99 15:36 ? 00:00:04 python3 -u test.py
jenkins 1550 1464 99 15:36 ? 00:00:05 [python3] # kill 후 -> 1550 프로세스 남아있음
jenkins 1550 1464 83 15:36 ? 00:00:05 [python3] <defunct> # kill 후 -> 1550 프로세스 남아있음
'Python' 카테고리의 다른 글
[python] UnicodeDecodeError: 'utf-8' codec can't decode byte 해결 방법 (0) | 2022.11.11 |
---|