Skip to content

Commit

Permalink
fix robyn on windows - remove process forking(#261)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
sansyrox authored Aug 11, 2022
1 parent 787ec93 commit 5fa1db2
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 49 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build-CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "robyn"
version = "0.17.1"
version = "0.17.2"
authors = ["Sanskar Jethi <[email protected]>"]
edition = "2018"
description = "A web server that is fast!"
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "robyn"
version = "0.17.1"
version = "0.17.2"
description = "A web server that is fast!"
authors = ["Sanskar Jethi <[email protected]>"]

Expand Down
60 changes: 41 additions & 19 deletions robyn/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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,
Expand All @@ -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()
Expand Down
16 changes: 8 additions & 8 deletions robyn/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
37 changes: 22 additions & 15 deletions robyn/processpool.py
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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()

Expand Down Expand Up @@ -81,3 +87,4 @@ def spawn_process(
loop.run_forever()
except KeyboardInterrupt:
loop.close()

1 change: 1 addition & 0 deletions robyn/robyn.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Server:
handler: Callable,
is_async: bool,
number_of_params: int,
const: bool,
) -> None:
pass
def add_middleware_route(
Expand Down

0 comments on commit 5fa1db2

Please sign in to comment.