Another day my friend told me he is using wsgiref.simple_server and asked if doit could be used to auto-reload the server. My first answer was do not use wsgiref :)
But you might prefer to use wsgiref & doit for for auto-reload for two reasons. doit can be bundled in a single file and included in the project. You might want to have explicit control on when the server should be reloaded.
server.py:
from wsgiref.simple_server import make_server, demo_app httpd = make_server('', 8000, demo_app) print "Serving HTTP on port 8000..." # Respond to requests until process is killed httpd.serve_forever()
dodo.py:
import subprocess import glob import os import signal def start_server(server_cmd, pid_filename, restart=False): # check the server is running if os.path.exists(pid_filename): if restart: stop_server(pid_filename) else: msg = "It seems the server is already running, check the file %s" print msg % pid_filename return False # start server process = subprocess.Popen(server_cmd.split()) # create pid file with open(pid_filename, 'w') as pid_file: pid_file.write(str(process.pid)) return True def stop_server(pid_filename): # check server if is running if not os.path.exists(pid_filename): return # try to terminate/stop server's process with open(pid_filename) as pid_file: pid = int(pid_file.read()) try: os.kill(pid, signal.SIGTERM) except OSError: pass #ignore errors if process does not exist # remove pid file os.unlink(pid_filename) ######################################## DOIT_CONFIG = {'default_tasks': ['restart']} PID_FILENAME = 'pid.txt' START_SERVER = 'python server.py' def task_start(): return {'actions': [(start_server, (START_SERVER, PID_FILENAME,))]} def task_stop(): return {'actions': [(stop_server, (PID_FILENAME,))]} def task_restart(): return {'actions': [(start_server, (START_SERVER, PID_FILENAME, True))], 'file_dep': glob.glob('*.py'), 'uptodate': [False], }
In order to do a auto-reload/restart the server we need to be able to start and stop the server with two independent commands.
So when starting the server we create a text file containing the PID of the process server.
The start_server funcion contains a boolean parameter ‘restart’ to control the behaviour when there is already a pid file.
task_restart
Usually ‘file_dep’ is used to indicated when a task is up-to-date but in this case we use it just to trigger a re-execution of the task in the ‘auto’ mode.
So apart from the action to restart the server the task’s file_dep controls which files to watch for modifications. Since we want always want to start the server when the task is called we need to add the ‘uptodate’ parameter to be false.
To use it just type:
$ doit auto restart
Hey, nice post!
Two questions:
1. usually there are multiple modules and packages under a server, but glob.glob is not descending into the directory tree – is there any other support in doit than getting the file_dep list manually by ourselves?
2. I am not totally clear on ‘uptodate’ – isn’t task_restart fired anyways if any of the file dependencies changed?
1) glob is not part of doit. you can use something else: http://stackoverflow.com/questions/2186525/use-a-glob-to-find-files-recursively-in-python or http://walkdir.readthedocs.org/en/latest/index.html
2) look at this case
* start the server with: $doit auto restart
* stop it with: Ctrl+C
* start the server again with: $ doit auto restart => the server would not start because the ‘restart’ task is up-to-date (none of the dependencies changed). so it needs this ‘uptodate’ set to False to indicate it should always run.