refactor: address PR review comments

1. Split respawning logic from reap_dirty_arbiter() into manage_dirty_arbiter()
   to avoid respawning during shutdown/re-exec (follows reap_workers pattern)

2. Reduce public API surface in __all__:
   - Keep errors, DirtyApp, client functions as public
   - Internal protocol helpers remain importable from submodules
   - DirtyArbiter and set_dirty_socket_path kept for gunicorn core
This commit is contained in:
Benoit Chesneau 2026-01-24 03:04:07 +01:00
parent 06aba09251
commit 3d9382b07c
2 changed files with 21 additions and 35 deletions

View File

@ -224,6 +224,7 @@ class Arbiter:
self.murder_workers()
self.manage_workers()
self.manage_dirty_arbiter()
except (StopIteration, KeyboardInterrupt):
self.halt()
except HaltServer as inst:
@ -764,7 +765,7 @@ class Arbiter:
sys.exit(0)
except SystemExit:
raise
except Exception as e:
except Exception:
self.log.exception("Exception in dirty arbiter process")
sys.exit(-1)
@ -810,12 +811,18 @@ class Arbiter:
self.dirty_arbiter_pid = 0
self.dirty_arbiter = None
# Respawn if we're still running and dirty workers are configured
if self.cfg.dirty_workers > 0 and self.cfg.dirty_apps:
self.log.info("Respawning dirty arbiter...")
self.spawn_dirty_arbiter()
except OSError as e:
if e.errno == errno.ECHILD:
self.dirty_arbiter_pid = 0
self.dirty_arbiter = None
def manage_dirty_arbiter(self):
"""\
Maintain the dirty arbiter process by respawning if needed.
"""
if self.dirty_arbiter_pid:
return # Already running
if self.cfg.dirty_workers > 0 and self.cfg.dirty_apps:
self.log.info("Spawning dirty arbiter...")
self.spawn_dirty_arbiter()

View File

@ -27,31 +27,20 @@ from .errors import (
DirtyProtocolError,
)
from .protocol import (
DirtyProtocol,
make_request,
make_response,
make_error_response,
)
from .app import DirtyApp
from .app import (
DirtyApp,
load_dirty_app,
load_dirty_apps,
)
from .worker import DirtyWorker
from .arbiter import DirtyArbiter
from .client import (
DirtyClient,
get_dirty_client,
get_dirty_client_async,
set_dirty_socket_path,
get_dirty_socket_path,
close_dirty_client,
close_dirty_client_async,
)
# Internal imports used by gunicorn core (not part of public API)
from .arbiter import DirtyArbiter
__all__ = [
# Errors
"DirtyError",
@ -61,25 +50,15 @@ __all__ = [
"DirtyAppError",
"DirtyAppNotFoundError",
"DirtyProtocolError",
# Protocol
"DirtyProtocol",
"make_request",
"make_response",
"make_error_response",
# App
# App base class
"DirtyApp",
"load_dirty_app",
"load_dirty_apps",
# Worker
"DirtyWorker",
# Arbiter
"DirtyArbiter",
# Client
"DirtyClient",
"get_dirty_client",
"get_dirty_client_async",
"set_dirty_socket_path",
"get_dirty_socket_path",
"close_dirty_client",
"close_dirty_client_async",
# Internal (used by gunicorn core)
"DirtyArbiter",
"set_dirty_socket_path",
]