mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-07 21:21:30 +08:00
feat(companion): Add states and CompanionConfig with config hash
This commit is contained in:
parent
3f479157d7
commit
2241dd4031
@ -664,8 +664,8 @@ No per-companion logic in Arbiter.
|
|||||||
|
|
||||||
## 20. Implementation Tasks
|
## 20. Implementation Tasks
|
||||||
|
|
||||||
- [ ] Add companion config settings in `gunicorn/config.py`.
|
- [x] Add companion config settings in `gunicorn/config.py`.
|
||||||
- [ ] Add config validation for `companion_workers`.
|
- [x] Add config validation for `companion_workers`.
|
||||||
- [ ] Add `CompanionConfig` and config hash generation.
|
- [ ] Add `CompanionConfig` and config hash generation.
|
||||||
- [ ] Add public process states.
|
- [ ] Add public process states.
|
||||||
- [ ] Add `CompanionProcess` runtime state.
|
- [ ] Add `CompanionProcess` runtime state.
|
||||||
|
|||||||
10
gunicorn/companion/__init__.py
Normal file
10
gunicorn/companion/__init__.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#
|
||||||
|
# This file is part of gunicorn released under the MIT license.
|
||||||
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
"""Companion process manager.
|
||||||
|
|
||||||
|
Gunicorn manages one extra child, the Companion Manager, which manages all
|
||||||
|
configured non-HTTP companion processes (RQ workers, scheduler, socket.io,
|
||||||
|
custom daemons). See ``docs/design/companion-process-manager.md``.
|
||||||
|
"""
|
||||||
85
gunicorn/companion/process.py
Normal file
85
gunicorn/companion/process.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#
|
||||||
|
# This file is part of gunicorn released under the MIT license.
|
||||||
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Public states, mimicking ``supervisorctl status``. The manager never
|
||||||
|
# exposes EXITED/FATAL/UNKNOWN; an exited companion is either STOPPED (manual)
|
||||||
|
# or BACKOFF (waiting to restart).
|
||||||
|
STOPPED = "STOPPED"
|
||||||
|
STARTING = "STARTING"
|
||||||
|
RUNNING = "RUNNING"
|
||||||
|
BACKOFF = "BACKOFF"
|
||||||
|
STOPPING = "STOPPING"
|
||||||
|
|
||||||
|
PUBLIC_STATES = (STOPPED, STARTING, RUNNING, BACKOFF, STOPPING)
|
||||||
|
|
||||||
|
|
||||||
|
class CompanionConfig:
|
||||||
|
"""Validated, normalized config for a single companion.
|
||||||
|
|
||||||
|
Built from one entry of ``companion_workers`` with global defaults already
|
||||||
|
applied. ``config_hash`` is a stable digest of every field; the manager
|
||||||
|
restarts a companion whenever its hash changes on reread.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
target,
|
||||||
|
cwd=None,
|
||||||
|
env=None,
|
||||||
|
stop_signal="SIGTERM",
|
||||||
|
stop_timeout=60,
|
||||||
|
reload_timeout=60,
|
||||||
|
stdout=None,
|
||||||
|
stderr=None,
|
||||||
|
startsecs=1,
|
||||||
|
):
|
||||||
|
self.name = name
|
||||||
|
self.target = target
|
||||||
|
self.cwd = cwd
|
||||||
|
self.env = dict(env or {})
|
||||||
|
self.stop_signal = stop_signal
|
||||||
|
self.stop_timeout = stop_timeout
|
||||||
|
self.reload_timeout = reload_timeout
|
||||||
|
self.stdout = stdout
|
||||||
|
self.stderr = stderr
|
||||||
|
self.startsecs = startsecs
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
"name": self.name,
|
||||||
|
"target": self.target,
|
||||||
|
"cwd": self.cwd,
|
||||||
|
"env": self.env,
|
||||||
|
"stop_signal": self.stop_signal,
|
||||||
|
"stop_timeout": self.stop_timeout,
|
||||||
|
"reload_timeout": self.reload_timeout,
|
||||||
|
"stdout": self.stdout,
|
||||||
|
"stderr": self.stderr,
|
||||||
|
"startsecs": self.startsecs,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config_hash(self):
|
||||||
|
# Sort keys so dict ordering never changes the digest. A callable
|
||||||
|
# target has no stable repr across runs, so use its qualified name.
|
||||||
|
data = self.to_dict()
|
||||||
|
data["target"] = self._target_key(self.target)
|
||||||
|
blob = json.dumps(data, sort_keys=True, default=str)
|
||||||
|
return hashlib.sha256(blob.encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _target_key(target):
|
||||||
|
if callable(target):
|
||||||
|
mod = getattr(target, "__module__", "")
|
||||||
|
qual = getattr(target, "__qualname__", repr(target))
|
||||||
|
return "%s:%s" % (mod, qual)
|
||||||
|
return str(target)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<CompanionConfig %s>" % self.name
|
||||||
Loading…
x
Reference in New Issue
Block a user