From 5fa1db21a4d6aba1acf53a91ffd49a48921a5c8b Mon Sep 17 00:00:00 2001 From: Sanskar Jethi Date: Thu, 11 Aug 2022 21:56:21 +0100 Subject: [PATCH] fix robyn on windows - remove process forking(#261) * chore: Add more type info * Fix multiprocessing in windows * Try apt instead of apt-get * fix: remove multiprocessing from windwos TODO: check how everything behaves on passing the --processes flag * fix: join unstarted process on windows * fix(__init__.py): hopefully fixes windows launch * rename to the final version --- .github/workflows/build-CI.yml | 8 ++--- Cargo.lock | 2 +- Cargo.toml | 2 +- pyproject.toml | 2 +- robyn/__init__.py | 60 +++++++++++++++++++++++----------- robyn/__init__.pyi | 16 ++++----- robyn/processpool.py | 37 ++++++++++++--------- robyn/robyn.pyi | 1 + 8 files changed, 79 insertions(+), 49 deletions(-) diff --git a/.github/workflows/build-CI.yml b/.github/workflows/build-CI.yml index 5cf89ea9a..7bb1cc218 100644 --- a/.github/workflows/build-CI.yml +++ b/.github/workflows/build-CI.yml @@ -147,12 +147,12 @@ jobs: dockerRunArgs: | --volume "${PWD}/dist:/artifacts" install: | - apt-get update -y - apt-get install -y --no-install-recommends software-properties-common + apt update -y + apt install -y --no-install-recommends software-properties-common add-apt-repository ppa:deadsnakes/ppa - apt-get update -y + apt update -y PYTHON=python${{ matrix.python.version }} - apt-get install -y $PYTHON $PYTHON-distutils $PYTHON-venv + apt install -y $PYTHON $PYTHON-distutils $PYTHON-venv run: | ls -lrth /artifacts PYTHON=python${{ matrix.python.version }} diff --git a/Cargo.lock b/Cargo.lock index d209c2239..fc4831b4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1229,7 +1229,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "robyn" -version = "0.17.1" +version = "0.17.2" dependencies = [ "actix", "actix-files", diff --git a/Cargo.toml b/Cargo.toml index d2842c35e..50813495a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "robyn" -version = "0.17.1" +version = "0.17.2" authors = ["Sanskar Jethi "] edition = "2018" description = "A web server that is fast!" diff --git a/pyproject.toml b/pyproject.toml index d6442bb38..5a785df5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ name = "robyn" -version = "0.17.1" +version = "0.17.2" description = "A web server that is fast!" authors = ["Sanskar Jethi "] diff --git a/robyn/__init__.py b/robyn/__init__.py index 2238c5a50..d6013932a 100644 --- a/robyn/__init__.py +++ b/robyn/__init__.py @@ -2,21 +2,20 @@ import logging import multiprocessing as mp import os +import sys from multiprocess import Process from watchdog.observers import Observer from robyn.events import Events -from .argument_parser import ArgumentParser -from .dev_event_handler import EventHandler -from .log_colors import Colors -from .processpool import spawn_process -from .responses import jsonify, static_file +from robyn.argument_parser import ArgumentParser +from robyn.dev_event_handler import EventHandler +from robyn.log_colors import Colors +from robyn.processpool import spawn_process +from robyn.responses import jsonify, static_file -from .robyn import SocketHeld -from .router import MiddlewareRouter, Router, WebSocketRouter -from .ws import WS - -mp.allow_connection_pickling() +from robyn.robyn import SocketHeld +from robyn.router import MiddlewareRouter, Router, WebSocketRouter +from robyn.ws import WS logger = logging.getLogger(__name__) @@ -104,14 +103,26 @@ def start(self, url="127.0.0.1", port=5000): :param port int: reperesents the port number at which the server is listening """ + def init_processpool(socket): + + process_pool = [] + if sys.platform.startswith("win32"): + spawn_process( + self.directories, + self.headers, + self.router.get_routes(), + self.middleware_router.get_routes(), + self.web_socket_router.get_routes(), + self.event_handlers, + socket, + workers, + ) + + return process_pool - if not self.dev: - processes = [] - workers = self.workers - socket = SocketHeld(url, port) for _ in range(self.processes): copied_socket = socket.try_clone() - p = Process( + process = Process( target=spawn_process, args=( self.directories, @@ -124,18 +135,29 @@ def start(self, url="127.0.0.1", port=5000): workers, ), ) - p.start() - processes.append(p) + process.start() + process_pool.append(process) + + return process_pool + + mp.allow_connection_pickling() + + if not self.dev: + workers = self.workers + socket = SocketHeld(url, port) + + process_pool = init_processpool(socket) logger.info(f"{Colors.HEADER}Starting up \n{Colors.ENDC}") logger.info(f"{Colors.OKGREEN}Press Ctrl + C to stop \n{Colors.ENDC}") try: - for process in processes: + for process in process_pool: process.join() except KeyboardInterrupt: logger.info(f"{Colors.BOLD}{Colors.OKGREEN} Terminating server!! {Colors.ENDC}") - for process in processes: + for process in process_pool: process.kill() + else: event_handler = EventHandler(self.file_path) event_handler.start_server_first_time() diff --git a/robyn/__init__.pyi b/robyn/__init__.pyi index 3c8f50fc4..cb1762404 100644 --- a/robyn/__init__.pyi +++ b/robyn/__init__.pyi @@ -9,14 +9,14 @@ from watchdog.observers import Observer from robyn.events import Events -from .argument_parser import ArgumentParser -from .dev_event_handler import EventHandler -from .log_colors import Colors -from .processpool import spawn_process -from .responses import jsonify, static_file -from .robyn import Server, SocketHeld -from .router import MiddlewareRouter, Router, WebSocketRouter -from .ws import WS +from robyn.argument_parser import ArgumentParser +from robyn.dev_event_handler import EventHandler +from robyn.log_colors import Colors +from robyn.processpool import spawn_process +from robyn.responses import jsonify, static_file +from robyn.robyn import Server, SocketHeld +from robyn.router import MiddlewareRouter, Router, WebSocketRouter +from robyn.ws import WS class Robyn: diff --git a/robyn/processpool.py b/robyn/processpool.py index ed1db0ed5..0f34040c4 100644 --- a/robyn/processpool.py +++ b/robyn/processpool.py @@ -1,13 +1,30 @@ import asyncio import logging import multiprocessing as mp +from multiprocessing.process import AuthenticationString import sys -from .events import Events -from .robyn import Server +from robyn.events import Events +from robyn.robyn import Server +from copy import deepcopy -mp.allow_connection_pickling() + +def initialize_event_loop(): + # platform_name = platform.machine() + if sys.platform.startswith("win32") or sys.platform.startswith("linux-cross"): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + return loop + else: + # uv loop doesn't support windows or arm machines at the moment + # but uv loop is much faster than native asyncio + import uvloop + + uvloop.install() + loop = uvloop.new_event_loop() + asyncio.set_event_loop(loop) + return loop def spawn_process( @@ -28,18 +45,7 @@ def spawn_process( :param workers number: This is the name given to the process to identify the process """ - # platform_name = platform.machine() - if sys.platform.startswith("win32") or sys.platform.startswith("linux-cross"): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - else: - # uv loop doesn't support windows or arm machines at the moment - # but uv loop is much faster than native asyncio - import uvloop - - uvloop.install() - loop = uvloop.new_event_loop() - asyncio.set_event_loop(loop) + loop = initialize_event_loop() server = Server() @@ -81,3 +87,4 @@ def spawn_process( loop.run_forever() except KeyboardInterrupt: loop.close() + diff --git a/robyn/robyn.pyi b/robyn/robyn.pyi index fd4d0de74..94e648636 100644 --- a/robyn/robyn.pyi +++ b/robyn/robyn.pyi @@ -28,6 +28,7 @@ class Server: handler: Callable, is_async: bool, number_of_params: int, + const: bool, ) -> None: pass def add_middleware_route(