mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
New on_reload server hook to customize how SIGHUPs spawn new workers.
This commit is contained in:
parent
4879005cc1
commit
d6560726c5
@ -448,6 +448,21 @@ def start_server(server):
|
|||||||
<p>Called just after the server is started.</p>
|
<p>Called just after the server is started.</p>
|
||||||
<p>The callable needs to accept a single instance variable for the Arbiter.</p>
|
<p>The callable needs to accept a single instance variable for the Arbiter.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="section" id="on-reload">
|
||||||
|
<h4><a class="toc-backref" href="#contents">on_reload</a></h4>
|
||||||
|
<ul>
|
||||||
|
<li><pre class="first literal-block">
|
||||||
|
def on_reload(server):
|
||||||
|
for i in range(server.app.cfg.workers):
|
||||||
|
server.spawn_worker()
|
||||||
|
</pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>Called during a reload from a SIGHUP signal.
|
||||||
|
This callback should create an appropriate number of new workers.
|
||||||
|
Old workers will be killed automatically by gunicorn, so it is not required to do so here.</p>
|
||||||
|
<p>The callable needs to accept a single instance variable for the Arbiter.</p>
|
||||||
|
</div>
|
||||||
<div class="section" id="pre-fork">
|
<div class="section" id="pre-fork">
|
||||||
<h4><a class="toc-backref" href="#contents">pre_fork</a></h4>
|
<h4><a class="toc-backref" href="#contents">pre_fork</a></h4>
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@ -337,17 +337,17 @@ class Arbiter(object):
|
|||||||
"""
|
"""
|
||||||
if self.pidfile is not None:
|
if self.pidfile is not None:
|
||||||
self.pidfile.rename("%s.oldbin" % self.pidfile.fname)
|
self.pidfile.rename("%s.oldbin" % self.pidfile.fname)
|
||||||
|
|
||||||
self.reexec_pid = os.fork()
|
self.reexec_pid = os.fork()
|
||||||
if self.reexec_pid != 0:
|
if self.reexec_pid != 0:
|
||||||
self.master_name = "Old Master"
|
self.master_name = "Old Master"
|
||||||
return
|
return
|
||||||
|
|
||||||
os.environ['GUNICORN_FD'] = str(self.LISTENER.fileno())
|
os.environ['GUNICORN_FD'] = str(self.LISTENER.fileno())
|
||||||
os.chdir(self.START_CTX['cwd'])
|
os.chdir(self.START_CTX['cwd'])
|
||||||
self.cfg.pre_exec(self)
|
self.cfg.pre_exec(self)
|
||||||
os.execvpe(self.START_CTX[0], self.START_CTX['args'], os.environ)
|
os.execvpe(self.START_CTX[0], self.START_CTX['args'], os.environ)
|
||||||
|
|
||||||
def reload(self):
|
def reload(self):
|
||||||
old_address = self.cfg.address
|
old_address = self.cfg.address
|
||||||
|
|
||||||
@ -362,8 +362,7 @@ class Arbiter(object):
|
|||||||
self.log.info("Listening at: %s", self.LISTENER)
|
self.log.info("Listening at: %s", self.LISTENER)
|
||||||
|
|
||||||
# spawn new workers with new app & conf
|
# spawn new workers with new app & conf
|
||||||
for i in range(self.app.cfg.workers):
|
self.cfg.on_reload(self)
|
||||||
self.spawn_worker()
|
|
||||||
|
|
||||||
# unlink pidfile
|
# unlink pidfile
|
||||||
if self.pidfile is not None:
|
if self.pidfile is not None:
|
||||||
@ -388,8 +387,7 @@ class Arbiter(object):
|
|||||||
"""
|
"""
|
||||||
for (pid, worker) in self.WORKERS.items():
|
for (pid, worker) in self.WORKERS.items():
|
||||||
try:
|
try:
|
||||||
diff = time.time() - os.fstat(worker.tmp.fileno()).st_ctime
|
if time.time() - worker.tmp.last_update() <= self.timeout:
|
||||||
if diff <= self.timeout:
|
|
||||||
continue
|
continue
|
||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
@ -446,7 +444,7 @@ class Arbiter(object):
|
|||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid != 0:
|
if pid != 0:
|
||||||
self.WORKERS[pid] = worker
|
self.WORKERS[pid] = worker
|
||||||
return
|
return pid
|
||||||
|
|
||||||
# Process Child
|
# Process Child
|
||||||
worker_pid = os.getpid()
|
worker_pid = os.getpid()
|
||||||
|
|||||||
@ -637,6 +637,21 @@ class OnStarting(Setting):
|
|||||||
The callable needs to accept a single instance variable for the Arbiter.
|
The callable needs to accept a single instance variable for the Arbiter.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
class OnReload(Setting):
|
||||||
|
name = "on_reload"
|
||||||
|
section = "Server Hooks"
|
||||||
|
validator = validate_callable(1)
|
||||||
|
type = "callable"
|
||||||
|
def on_reload(server):
|
||||||
|
for i in range(server.app.cfg.workers):
|
||||||
|
server.spawn_worker()
|
||||||
|
default = staticmethod(on_reload)
|
||||||
|
desc = """\
|
||||||
|
Called to recycle workers during a reload via SIGHUP.
|
||||||
|
|
||||||
|
The callable needs to accept a single instance variable for the Arbiter.
|
||||||
|
"""
|
||||||
|
|
||||||
class WhenReady(Setting):
|
class WhenReady(Setting):
|
||||||
name = "when_ready"
|
name = "when_ready"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
|
|||||||
@ -37,6 +37,9 @@ class WorkerTmp(object):
|
|||||||
self._tmp.truncate(0)
|
self._tmp.truncate(0)
|
||||||
os.write(self._tmp.fileno(), "X")
|
os.write(self._tmp.fileno(), "X")
|
||||||
|
|
||||||
|
def last_update(self):
|
||||||
|
return os.fstat(self._tmp.fileno()).st_ctime
|
||||||
|
|
||||||
def fileno(self):
|
def fileno(self):
|
||||||
return self._tmp.fileno()
|
return self._tmp.fileno()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user