-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add options to purge big workers #3252
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,6 +63,7 @@ def __init__(self, app): | |
self.reexec_pid = 0 | ||
self.master_pid = 0 | ||
self.master_name = "Master" | ||
self.next_prune = None | ||
|
||
cwd = util.getcwd() | ||
|
||
|
@@ -203,6 +204,13 @@ def run(self): | |
|
||
while True: | ||
self.maybe_promote_master() | ||
if 0 < self.cfg.prune_seconds: | ||
if self.next_prune is None: | ||
self.next_prune = time.monotonic() + self.cfg.prune_seconds | ||
elif self.next_prune <= time.monotonic(): | ||
self.prune_worker() | ||
self.next_prune += self.cfg.prune_seconds * ( | ||
0.95 + 0.10 * random.random()) | ||
Comment on lines
+207
to
+213
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if it would make sense to put all this logic into prune_worker? I mean, something like: def prune_worker(self):
"""\
Kill the worker with highest prune score
"""
if self.cfg.prune_seconds <= 0:
return
if self.next_prune is None:
self.next_prune = time.monotonic() + self.cfg.prune_seconds
if time.monotonic() < self.next_prune:
return
maxi = self.cfg.prune_floor
victim = 0
for pid in list(self.WORKERS.keys()):
score = self.cfg.prune_function(pid)
if maxi < score:
maxi = score
victim = pid
if victim != 0:
self.log.info(f"Pruning worker (pid: {victim}) with score {score}")
self.kill_worker(victim, signal.SIGTERM)
self.next_prune += self.cfg.prune_seconds * random.uniform(0.95, 1.05) ... and then call I had two other minor suggestions as well (incorporated in the proposed method above):
|
||
|
||
sig = self.SIG_QUEUE.pop(0) if self.SIG_QUEUE else None | ||
if sig is None: | ||
|
@@ -486,6 +494,22 @@ def reload(self): | |
# manage workers | ||
self.manage_workers() | ||
|
||
def prune_worker(self): | ||
"""\ | ||
Kill the worker with highest prune score | ||
""" | ||
workers = list(self.WORKERS.items()) | ||
maxi = self.cfg.prune_floor | ||
victim = 0 | ||
for pid, _ in workers: | ||
score = self.cfg.prune_function(pid) | ||
if maxi < score: | ||
maxi = score | ||
victim = pid | ||
if victim != 0: | ||
self.log.info(f"Pruning worker (pid: {victim}) with score {score}") | ||
self.kill_worker(victim, signal.SIGTERM) | ||
|
||
def murder_workers(self): | ||
"""\ | ||
Kill unused/idle workers | ||
|
@@ -586,9 +610,9 @@ def manage_workers(self): | |
|
||
def spawn_worker(self): | ||
self.worker_age += 1 | ||
worker = self.worker_class(self.worker_age, self.pid, self.LISTENERS, | ||
self.app, self.timeout / 2.0, | ||
self.cfg, self.log) | ||
worker = self.worker_class( | ||
self.worker_age, self.pid, self.LISTENERS, self.app, | ||
self.timeout / 2.0, self.cfg, self.log) | ||
Comment on lines
+613
to
+615
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks like unrelated whitespace changes |
||
self.cfg.pre_fork(self, worker) | ||
pid = os.fork() | ||
if pid != 0: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does not appear to match documentation: 0.95+0.10 = 1.05 > 100%. But the general idea of averaging out late firing timers seems much more reasonable, so I'd change documentation to clarify that its not the pause between invocations but the average interval.