mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-02 10:41:30 +08:00
fix(tests): use process groups for reliable signal handling in PyPy
- Use preexec_fn=os.setsid to create new process group - Send signals to process group with os.killpg() instead of single process - Add explicit timeout and graceful-timeout to gunicorn command - Fixes test failures on PyPy 3.10 where signals weren't propagating properly
This commit is contained in:
parent
cd77bcc941
commit
63df19bd5c
@ -93,15 +93,19 @@ def gunicorn_server(app_module):
|
|||||||
'--access-logfile', '-',
|
'--access-logfile', '-',
|
||||||
'--error-logfile', '-',
|
'--error-logfile', '-',
|
||||||
'--log-level', 'info',
|
'--log-level', 'info',
|
||||||
|
'--timeout', '30',
|
||||||
|
'--graceful-timeout', '30',
|
||||||
app_name
|
app_name
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Use setsid to create new process group for proper signal handling
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
cmd,
|
cmd,
|
||||||
cwd=app_dir,
|
cwd=app_dir,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
env={**os.environ, 'PYTHONPATH': app_dir}
|
env={**os.environ, 'PYTHONPATH': app_dir},
|
||||||
|
preexec_fn=os.setsid
|
||||||
)
|
)
|
||||||
|
|
||||||
# Wait for server to start
|
# Wait for server to start
|
||||||
@ -113,13 +117,19 @@ def gunicorn_server(app_module):
|
|||||||
|
|
||||||
yield proc, port
|
yield proc, port
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup - use process group kill for better cleanup
|
||||||
if proc.poll() is None:
|
if proc.poll() is None:
|
||||||
proc.terminate()
|
try:
|
||||||
|
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
|
||||||
|
except (ProcessLookupError, OSError):
|
||||||
|
pass
|
||||||
try:
|
try:
|
||||||
proc.wait(timeout=5)
|
proc.wait(timeout=5)
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
proc.kill()
|
try:
|
||||||
|
os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
|
||||||
|
except (ProcessLookupError, OSError):
|
||||||
|
pass
|
||||||
proc.wait()
|
proc.wait()
|
||||||
|
|
||||||
|
|
||||||
@ -141,8 +151,11 @@ class TestSignalHandlingIntegration:
|
|||||||
response = make_request('127.0.0.1', port)
|
response = make_request('127.0.0.1', port)
|
||||||
assert b'Hello, World!' in response
|
assert b'Hello, World!' in response
|
||||||
|
|
||||||
# Send SIGTERM
|
# Send SIGTERM to the process group for reliable signal delivery
|
||||||
proc.send_signal(signal.SIGTERM)
|
try:
|
||||||
|
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
|
||||||
|
except (ProcessLookupError, OSError):
|
||||||
|
proc.send_signal(signal.SIGTERM)
|
||||||
|
|
||||||
# Wait for process to exit
|
# Wait for process to exit
|
||||||
try:
|
try:
|
||||||
@ -160,8 +173,11 @@ class TestSignalHandlingIntegration:
|
|||||||
response = make_request('127.0.0.1', port)
|
response = make_request('127.0.0.1', port)
|
||||||
assert b'Hello, World!' in response
|
assert b'Hello, World!' in response
|
||||||
|
|
||||||
# Send SIGINT
|
# Send SIGINT to the process group for reliable signal delivery
|
||||||
proc.send_signal(signal.SIGINT)
|
try:
|
||||||
|
os.killpg(os.getpgid(proc.pid), signal.SIGINT)
|
||||||
|
except (ProcessLookupError, OSError):
|
||||||
|
proc.send_signal(signal.SIGINT)
|
||||||
|
|
||||||
# Wait for process to exit
|
# Wait for process to exit
|
||||||
try:
|
try:
|
||||||
@ -179,7 +195,7 @@ class TestSignalHandlingIntegration:
|
|||||||
response = make_request('127.0.0.1', port)
|
response = make_request('127.0.0.1', port)
|
||||||
assert b'Hello, World!' in response
|
assert b'Hello, World!' in response
|
||||||
|
|
||||||
# Send SIGHUP
|
# Send SIGHUP to the master process (not process group - only master handles reload)
|
||||||
proc.send_signal(signal.SIGHUP)
|
proc.send_signal(signal.SIGHUP)
|
||||||
|
|
||||||
# Wait a moment for reload
|
# Wait a moment for reload
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user