Fix proper termination of gunicorn when it hangs (#30188)
During refactoring of the internal API background test, it was
found that the SIGKILL termination of gunicorn in case it was not
responding to SIGTERM (introduced in #11734) has never been working
properly. The code assumed that gunicorn_master_process was
of the subprocess.Popen type and used .poll() method to check if the
process is still running and it would issue sigkill in such case.
However the Process we have there is a psutil.Process and it has
no poll() method - instead we can use is_running() method, which
has the added advantage that is_running() is also checking if the
pid has not been reused by another process after terminating the
original gunicorn.
The result of it was this error:
```
AttributeError: 'Process' object has no attribute 'poll'
```
(cherry picked from commit fd2db8856b36556b77d277a63c38c666816429c3)
diff --git a/airflow/cli/commands/webserver_command.py b/airflow/cli/commands/webserver_command.py
index a14f6a3..685cc42 100644
--- a/airflow/cli/commands/webserver_command.py
+++ b/airflow/cli/commands/webserver_command.py
@@ -425,14 +425,14 @@
# then have a copy of the app
run_args += ["--preload"]
- gunicorn_master_proc = None
+ gunicorn_master_proc: psutil.Process | None = None
def kill_proc(signum, _):
log.info("Received signal: %s. Closing gunicorn.", signum)
gunicorn_master_proc.terminate()
with suppress(TimeoutError):
gunicorn_master_proc.wait(timeout=30)
- if gunicorn_master_proc.poll() is not None:
+ if gunicorn_master_proc.is_running():
gunicorn_master_proc.kill()
sys.exit(0)