This article is based on the Django-2.1.x version series.
Preliminary test – After file changesserver
Automatic restart
Before we do that, why not take a look at how Django automatically restarts
start
When Django uses the runserver command, it starts two processes.
Runserver then executes the main calls the django/utils/autoreload py under the main method. As for why we are here, we will not elaborate on it in detail, but will explain it in a later chapter.
The main thread uses the os.stat method to get the last modification time of the file for comparison, and then restarts the Django service (that is, the child process).
About once a second.
# django/utils/autoreload py reloader_thread method
def reloader_thread() :.# listen for file changes
# -- Start
# Use the 'Pyinotify' module mainly here, because the current import may not be successful temporarily, use else block code
# USE_INOTIFY This value is False
if USE_INOTIFY:
fn = inotify_code_changed
else:
fn = code_changed
# -- End
while RUN_RELOADER:
change = fn()
if change == FILE_MODIFIED:
sys.exit(3) # force reload
elif change == I18N_MODIFIED:
reset_translations()
time.sleep(1)
Copy the code
Code_changed Returns True for restart based on whether the best modification time for each file has changed.
Parent and child processes & Multithreading
The code for the restart is in the python_reloader function
# django/utils/autoreload.py
def restart_with_reloader() :
import django.__main__
while True:
args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions]
if sys.argv[0] == django.__main__.__file__:
# The server was started with `python -m django runserver`.
args += ['-m'.'django']
args += sys.argv[1:]
else:
args += sys.argv
new_environ = {**os.environ, 'RUN_MAIN': 'true'}
exit_code = subprocess.call(args, env=new_environ)
ifexit_code ! =3:
return exit_code
def python_reloader(main_func, args, kwargs) :
# this variable is not used in the environment configuration at first, all else statement block is used
if os.environ.get("RUN_MAIN") = ="true":
Start a new thread to start the service
_thread.start_new_thread(main_func, args, kwargs)
try:
The program then moves down to monitor file changes
# file changes, exit the process, exit code feedback to the subprocess.call receiver...
reloader_thread()
except KeyboardInterrupt:
pass
else:
try:
The restart_with_reloader function sets the RUN_MAIN variable
exit_code = restart_with_reloader()
if exit_code < 0:
os.kill(os.getpid(), -exit_code)
else:
sys.exit(exit_code)
except KeyboardInterrupt:
pass
Copy the code
The program starts with an else statement block because there is no RUN_MAIN variable.
The subprocess.call method is used in the restart_with_reloader function to start the program (LLDB: Python3 manage.py runserver), now RUN_MAIN is True, then execute _thread.start_new_thread(main_func, args, kwargs) to start a new thread. This means that the Django service has been started.
If the child does not exit, it stays in the call method. If the child exits, the exit code is not 3, and the while is terminated. If not, the loop continues and the child process is recreated.
Detect file modification
The implementation of a function that detects file changes.
# django/utils/autoreload.py
def code_changed() :
global _mtimes, _win
Get all files
for filename in gen_filenames():
Check the status of each file through the OS module
stat = os.stat(filename)
Get the last modification time
mtime = stat.st_mtime
if _win:
mtime -= stat.st_ctime
if filename not in _mtimes:
_mtimes[filename] = mtime
continue
# compare whether to modify
ifmtime ! = _mtimes[filename]: _mtimes = {}try:
del _error_files[_error_files.index(filename)]
except ValueError:
pass
return I18N_MODIFIED if filename.endswith('.mo') else FILE_MODIFIED
return False
Copy the code
conclusion
This is how Django detects file changes to restart the service.
Create two processes with subprocess.call and environment variables. The master process is responsible for monitoring and restarting child processes. By starting a new thread (that is, a Django service) in the child process. The main thread monitors file changes and exits the child process through sys.exit(3). If the parent process does not obtain the exit code of 3, it continues to loop to create the child process. Otherwise, it exits the entire program.
Ok, here we go. We took the first step bravely, let’s move on to the next step!! ヾ (◍ ° ∇ ° ◍) ノ ゙