Mercurial > piecrust2
comparison piecrust/serving/wrappers.py @ 552:9612cfc6455a
serve: Rewrite of the Server-Sent Event code for build notifications.
At the moment the server monitors the asset directories, and notifies the
browser when an asset has changed and has been re-processed.
* Fix issues around long-running requests/threads which mess up the ability
to shutdown the server correctly with `CTRL-C` (see comments in code).
* Move the notification queue to each SSE producer, to support having multiple
pages open in a browser.
* Add JS/CSS for showing quick notifications about re-processed assets.
* Add support for hot-reloading CSS and pictures that have been re-processed.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sat, 08 Aug 2015 16:12:04 -0700 |
parents | fa3ee8a8ee2d |
children | cc6f3dbe3048 |
comparison
equal
deleted
inserted
replaced
551:f2b875ecc940 | 552:9612cfc6455a |
---|---|
1 import os | 1 import os |
2 import logging | |
3 import threading | |
4 import urllib.request | |
2 from piecrust.serving.server import Server | 5 from piecrust.serving.server import Server |
3 from piecrust.serving.procloop import _sse_abort | 6 |
7 | |
8 logger = logging.getLogger(__name__) | |
4 | 9 |
5 | 10 |
6 def run_werkzeug_server(root_dir, host, port, | 11 def run_werkzeug_server(root_dir, host, port, |
7 debug_piecrust=False, sub_cache_dir=None, | 12 debug_piecrust=False, sub_cache_dir=None, |
8 use_debugger=False, use_reloader=False): | 13 use_debugger=False, use_reloader=False): |
20 | 25 |
21 app = _get_piecrust_server(root_dir, | 26 app = _get_piecrust_server(root_dir, |
22 debug=debug_piecrust, | 27 debug=debug_piecrust, |
23 sub_cache_dir=sub_cache_dir, | 28 sub_cache_dir=sub_cache_dir, |
24 run_sse_check=_run_sse_check) | 29 run_sse_check=_run_sse_check) |
25 try: | 30 |
31 # We need to run Werkzeug in a background thread because we may have some | |
32 # SSE responses running. In theory we should be using a proper async | |
33 # server for this kind of stuff, but I'd rather avoid additional | |
34 # dependencies on stuff that's not necessarily super portable. | |
35 # Anyway we run the server in multi-threading mode, but the request | |
36 # threads are not set to `daemon` mode (and there's no way to set that | |
37 # flag without re-implementing `run_simple` apparently). So instead we | |
38 # run the server in a background thread so we keep the main thread to | |
39 # ourselves here, which means we can trap `KeyboardInterrupt`, and set | |
40 # a global flag that will kill all the long-running SSE threads and make | |
41 # this whole thing exit cleanly and properly (hopefully). | |
42 def _inner(): | |
26 run_simple(host, port, app, | 43 run_simple(host, port, app, |
27 threaded=True, | 44 threaded=True, |
28 use_debugger=use_debugger, | 45 use_debugger=use_debugger, |
29 use_reloader=use_reloader) | 46 use_reloader=use_reloader) |
47 | |
48 t = threading.Thread(name='WerkzeugServer', target=_inner) | |
49 t.start() | |
50 try: | |
51 while t.is_alive(): | |
52 t.join(0.5) | |
53 except KeyboardInterrupt: | |
54 shutdown_url = 'http://%s:%s/__piecrust_debug/werkzeug_shutdown' % ( | |
55 host, port) | |
56 logger.info("") | |
57 logger.info("Shutting down server...") | |
58 urllib.request.urlopen(shutdown_url) | |
30 finally: | 59 finally: |
31 _sse_abort.set() | 60 logger.debug("Terminating push notifications...") |
61 from piecrust.serving import procloop | |
62 procloop.server_shutdown = True | |
32 | 63 |
33 | 64 |
34 def run_gunicorn_server(root_dir, | 65 def run_gunicorn_server(root_dir, |
35 debug_piecrust=False, sub_cache_dir=None, | 66 debug_piecrust=False, sub_cache_dir=None, |
36 gunicorn_options=None): | 67 gunicorn_options=None): |