Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: live reloading when running as a module #858

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions robyn/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from robyn import status_codes
from robyn.argument_parser import Config
from robyn.authentication import AuthenticationHandler
from robyn.cli import start_dev_server
VishnuSanal marked this conversation as resolved.
Show resolved Hide resolved
from robyn.dependency_injection import DependencyMap
from robyn.env_populator import load_vars
from robyn.events import Events
Expand Down Expand Up @@ -56,8 +57,6 @@ def __init__(
"SERVER IS RUNNING IN VERBOSE/DEBUG MODE. Set --log-level to WARN to run in production mode.",
color=Colors.BLUE,
)
if self.config.dev:
exit("Dev mode is not supported in the python wrapper. Please use the CLI. e.g. python3 -m robyn app.py --dev ")

self.router = Router()
self.middleware_router = MiddlewareRouter()
Expand Down Expand Up @@ -225,21 +224,24 @@ def start(self, host: str = "127.0.0.1", port: int = 8080, _check_port: bool = T

mp.allow_connection_pickling()

run_processes(
host,
port,
self.directories,
self.request_headers,
self.router.get_routes(),
self.middleware_router.get_global_middlewares(),
self.middleware_router.get_route_middlewares(),
self.web_socket_router.get_routes(),
self.event_handlers,
self.config.workers,
self.config.processes,
self.response_headers,
open_browser,
)
if self.config.dev:
start_dev_server(self.config, self.config.file_path)
else:
run_processes(
host,
port,
self.directories,
self.request_headers,
self.router.get_routes(),
self.middleware_router.get_global_middlewares(),
self.middleware_router.get_route_middlewares(),
self.web_socket_router.get_routes(),
self.event_handlers,
self.config.workers,
self.config.processes,
self.response_headers,
open_browser,
)

def exception(self, exception_handler: Callable):
self.exception_handler = exception_handler
Expand Down
3 changes: 3 additions & 0 deletions robyn/argument_parser.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import argparse
import sys


class Config:
Expand Down Expand Up @@ -87,6 +88,8 @@ def __init__(self) -> None:
if arg.endswith(".py"):
VishnuSanal marked this conversation as resolved.
Show resolved Hide resolved
self.file_path = arg
break
else:
self.file_path = sys.argv[0]
VishnuSanal marked this conversation as resolved.
Show resolved Hide resolved

if self.dev and (self.processes != 1 or self.workers != 1):
raise Exception("--processes and --workers shouldn't be used with --dev")
Expand Down
2 changes: 1 addition & 1 deletion robyn/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def start_dev_server(config: Config, file_path: Optional[str] = None):
directory_path = absolute_file_path.parent

if config.dev and not os.environ.get("IS_RELOADER_RUNNING", False):
setup_reloader(str(directory_path), str(absolute_file_path))
setup_reloader(config, str(directory_path), str(absolute_file_path))
return


Expand Down
26 changes: 18 additions & 8 deletions robyn/reloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer

from robyn import Config
from robyn.logger import Colors, logger

dir_path = None
Expand Down Expand Up @@ -58,8 +59,8 @@ def clean_rust_binaries(rust_binaries: List[str]):
os.remove(file)


def setup_reloader(directory_path: str, file_path: str):
event_handler = EventHandler(file_path, directory_path)
def setup_reloader(config: Config, directory_path: str, file_path: str):
event_handler = EventHandler(config, file_path, directory_path)

event_handler.reload()

Expand Down Expand Up @@ -91,7 +92,8 @@ def terminating_signal_handler(_sig, _frame):


class EventHandler(FileSystemEventHandler):
def __init__(self, file_path: str, directory_path: str) -> None:
def __init__(self, config: Config, file_path: str, directory_path: str) -> None:
self.config = config
self.file_path = file_path
self.directory_path = directory_path
self.process = None # Keep track of the subprocess
Expand All @@ -115,11 +117,19 @@ def reload(self):
clean_rust_binaries(self.built_rust_binaries)
self.built_rust_binaries = compile_rust_files(self.directory_path)

self.process = subprocess.Popen(
[sys.executable, *arguments],
env=new_env,
start_new_session=False,
)
if self.config.dev and self.config.file_path is not None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not use self.file_path?

Then we don't need to pass in config.

Copy link
Contributor Author

@VishnuSanal VishnuSanal Jun 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we also need config.dev. should I pass it as a variable?

edit: we also need running_as_module now.

subprocess.call(f'cd {"/".join(self.config.file_path.split("/")[-2:-1])}', shell=True)
self.process = subprocess.Popen(
[sys.executable, "-m", self.config.file_path.split("/")[-2], *arguments],
VishnuSanal marked this conversation as resolved.
Show resolved Hide resolved
env=new_env,
start_new_session=False,
)
VishnuSanal marked this conversation as resolved.
Show resolved Hide resolved
else:
self.process = subprocess.Popen(
[sys.executable, *arguments],
env=new_env,
start_new_session=False,
)

self.last_reload = time.time()

Expand Down
Loading