Skip to content

Commit 4135b60

Browse files
committed
Implement fs watcher to implement server-portion of hot reloading for pip CLI
1 parent 7157180 commit 4135b60

File tree

1 file changed

+63
-8
lines changed

1 file changed

+63
-8
lines changed

mesop/bin/bin.py

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1+
import logging
12
import os
23
import sys
4+
import threading
5+
import time
36
from typing import Sequence
47

58
from absl import app, flags
69

710
import mesop.protos.ui_pb2 as pb
811
from mesop.cli.execute_module import execute_module, get_module_name_from_path
912
from mesop.exceptions import format_traceback
10-
from mesop.runtime import runtime
13+
from mesop.runtime import (
14+
enable_debug_mode,
15+
hot_reload_finished,
16+
reset_runtime,
17+
runtime,
18+
)
1119
from mesop.server.wsgi_app import create_app
1220

1321
FLAGS = flags.FLAGS
@@ -39,14 +47,61 @@ def main(argv: Sequence[str]):
3947
)
4048
sys.exit(1)
4149

42-
create_app(
43-
prod_mode=FLAGS.prod, run_block=lambda: execute_main_module(argv[1])
44-
).run()
45-
46-
47-
def execute_main_module(path_arg: str):
50+
if not FLAGS.prod:
51+
enable_debug_mode()
52+
53+
absolute_path = absolute_path = make_path_absolute(argv[1])
54+
app = create_app(
55+
prod_mode=FLAGS.prod,
56+
run_block=lambda: execute_main_module(absolute_path=absolute_path),
57+
)
58+
59+
# WARNING: this needs to run *after* the initial `execute_module`
60+
# has completed, otherwise there's a potential race condition where the
61+
# background thread and main thread are running `execute_module` which
62+
# leads to obscure hot reloading bugs.
63+
if not FLAGS.prod:
64+
print("Running with hot reload:")
65+
stdin_thread = threading.Thread(
66+
target=lambda: fs_watcher(absolute_path), name="mesop_fs_watcher_thread"
67+
)
68+
stdin_thread.daemon = True
69+
stdin_thread.start()
70+
71+
app.run()
72+
73+
74+
def fs_watcher(absolute_path: str):
75+
"""
76+
Naive filesystem watcher for the main module of the Mesop application.
77+
78+
In the future, we can watch for the entire directory, but this captures the main 80% case.
79+
"""
80+
last_modified = os.path.getmtime(absolute_path)
81+
while True:
82+
# Get the current modification time
83+
current_modified = os.path.getmtime(absolute_path)
84+
85+
# Compare the current modification time with the last modification time
86+
if current_modified != last_modified:
87+
# Update the last modification time
88+
last_modified = current_modified
89+
try:
90+
print("Hot reload: starting...")
91+
reset_runtime()
92+
execute_main_module(absolute_path=absolute_path)
93+
hot_reload_finished()
94+
print("Hot reload: finished!")
95+
except Exception as e:
96+
logging.log(
97+
logging.ERROR, "Could not hot reload due to error:", exc_info=e
98+
)
99+
100+
time.sleep(0.2)
101+
102+
103+
def execute_main_module(absolute_path: str):
48104
try:
49-
absolute_path = make_path_absolute(path_arg)
50105
execute_module(
51106
module_path=absolute_path,
52107
module_name=get_module_name_from_path(absolute_path),

0 commit comments

Comments
 (0)