3
# Copyright 2009 Facebook
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
17
"""A module to automatically restart the server when a module is modified.
19
This module depends on IOLoop, so it will not work in WSGI applications
32
_log = logging.getLogger('tornado.autoreload')
34
def start(io_loop=None, check_time=500):
35
"""Restarts the process automatically when a module is modified.
37
We run on the I/O loop, and restarting is a destructive operation,
38
so will terminate any pending requests.
40
io_loop = io_loop or ioloop.IOLoop.instance()
42
callback = functools.partial(_reload_on_update, io_loop, modify_times)
43
scheduler = ioloop.PeriodicCallback(callback, check_time, io_loop=io_loop)
47
_reload_attempted = False
49
def _reload_on_update(io_loop, modify_times):
50
global _reload_attempted
52
# We already tried to reload and it didn't work, so don't try again.
54
for module in sys.modules.values():
55
# Some modules play games with sys.modules (e.g. email/__init__.py
56
# in the standard library), and occasionally this can cause strange
57
# failures in getattr. Just ignore anything that's not an ordinary
59
if not isinstance(module, types.ModuleType): continue
60
path = getattr(module, "__file__", None)
62
if path.endswith(".pyc") or path.endswith(".pyo"):
65
modified = os.stat(path).st_mtime
68
if path not in modify_times:
69
modify_times[path] = modified
71
if modify_times[path] != modified:
72
_log.info("%s modified; restarting server", path)
73
_reload_attempted = True
74
for fd in io_loop._handlers.keys():
80
os.execv(sys.executable, [sys.executable] + sys.argv)
82
# Mac OS X versions prior to 10.6 do not support execv in
83
# a process that contains multiple threads. Instead of
84
# re-executing in the current process, start a new one
85
# and cause the current process to exit. This isn't
86
# ideal since the new process is detached from the parent
87
# terminal and thus cannot easily be killed with ctrl-C,
88
# but it's better than not being able to autoreload at
90
# Unfortunately the errno returned in this case does not
91
# appear to be consistent, so we can't easily check for
92
# this error specifically.
93
os.spawnv(os.P_NOWAIT, sys.executable,
94
[sys.executable] + sys.argv)