Enable pc prod without redis (#85)

* Make app callable

* Enable pc prod without redis

* Add missing code
This commit is contained in:
Nikhil Rao 2022-12-13 10:05:37 -08:00 committed by GitHub
parent 23fc3cadd9
commit d39bcc7d38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 12 deletions

View File

@ -74,6 +74,14 @@ class App(Base):
""" """
return f"<App state={self.state.__name__}>" return f"<App state={self.state.__name__}>"
def __call__(self) -> fastapi.FastAPI:
"""Run the backend api instance.
Returns:
The backend api.
"""
return self.api
def add_default_endpoints(self): def add_default_endpoints(self):
"""Add the default endpoints.""" """Add the default endpoints."""
# To test the server. # To test the server.

View File

@ -56,12 +56,10 @@ BUN_PATH = "$HOME/.bun/bin/bun"
INSTALL_BUN = "curl https://bun.sh/install | bash" INSTALL_BUN = "curl https://bun.sh/install | bash"
# Command to run the backend in dev mode. # Command to run the backend in dev mode.
RUN_BACKEND = "uvicorn --log-level critical --reload --host 0.0.0.0".split() RUN_BACKEND = "uvicorn --log-level critical --reload --host 0.0.0.0".split()
# The number of workers to run in production mode by default.
NUM_WORKERS = (os.cpu_count() or 1) * 2 + 1
# The default timeout when launching the gunicorn server. # The default timeout when launching the gunicorn server.
TIMEOUT = 120 TIMEOUT = 120
# The command to run the backend in production mode. # The command to run the backend in production mode.
RUN_BACKEND_PROD = f"gunicorn --worker-class uvicorn.workers.UvicornH11Worker --bind 0.0.0.0:8000 --workers {NUM_WORKERS} --threads {NUM_WORKERS} --preload --timeout {TIMEOUT} --log-level debug".split() RUN_BACKEND_PROD = f"gunicorn --worker-class uvicorn.workers.UvicornH11Worker --bind 0.0.0.0:8000 --preload --timeout {TIMEOUT} --log-level debug".split()
# Compiler variables. # Compiler variables.
# The extension for compiled Javascript files. # The extension for compiled Javascript files.

View File

@ -8,6 +8,8 @@ import traceback
from abc import ABC from abc import ABC
from typing import Any, Callable, ClassVar, Dict, List, Optional, Sequence, Set, Type from typing import Any, Callable, ClassVar, Dict, List, Optional, Sequence, Set, Type
from redis import Redis
from pynecone import constants, utils from pynecone import constants, utils
from pynecone.base import Base from pynecone.base import Base
from pynecone.event import Event, EventHandler, window_alert from pynecone.event import Event, EventHandler, window_alert
@ -476,7 +478,7 @@ class StateManager(Base):
token_expiration: int = constants.TOKEN_EXPIRATION token_expiration: int = constants.TOKEN_EXPIRATION
# The redis client to use. # The redis client to use.
redis: Any = None redis: Optional[Redis] = None
def setup(self, state: Type[State]): def setup(self, state: Type[State]):
"""Set up the state manager. """Set up the state manager.

View File

@ -29,6 +29,7 @@ from typing import (
import plotly.graph_objects as go import plotly.graph_objects as go
from plotly.io import to_json from plotly.io import to_json
from redis import Redis
from rich.console import Console from rich.console import Console
from pynecone import constants from pynecone import constants
@ -385,6 +386,20 @@ def run_frontend_prod(app) -> subprocess.Popen:
return subprocess.Popen(command, cwd=constants.WEB_DIR) return subprocess.Popen(command, cwd=constants.WEB_DIR)
def get_num_workers() -> int:
"""Get the number of backend worker processes.
Returns:
The number of backend worker processes.
"""
if get_redis() is None:
# If there is no redis, then just use 1 worker.
return 1
# Use the number of cores * 2 + 1.
return (os.cpu_count() or 1) * 2 + 1
def run_backend(app): def run_backend(app):
"""Run the backend. """Run the backend.
@ -403,7 +418,14 @@ def run_backend_prod(app) -> None:
Args: Args:
app: The app. app: The app.
""" """
command = constants.RUN_BACKEND_PROD + [f"{app.__name__}:{constants.API_VAR}"] num_workers = get_num_workers()
command = constants.RUN_BACKEND_PROD + [
"--workers",
str(num_workers),
"--threads",
str(num_workers),
f"{app.__name__}:{constants.APP_VAR}()",
]
subprocess.call(command) subprocess.call(command)
@ -918,20 +940,15 @@ def get_hydrate_event(state) -> str:
return get_event(state, constants.HYDRATE) return get_event(state, constants.HYDRATE)
def get_redis(): def get_redis() -> Optional[Redis]:
"""Get the redis client. """Get the redis client.
Returns: Returns:
The redis client. The redis client.
""" """
try:
import redis # type: ignore
except:
return None
config = get_config() config = get_config()
if config.redis_url is None: if config.redis_url is None:
return None return None
redis_url, redis_port = config.redis_url.split(":") redis_url, redis_port = config.redis_url.split(":")
print("Using redis at", config.redis_url) print("Using redis at", config.redis_url)
return redis.Redis(host=redis_url, port=int(redis_port), db=0) return Redis(host=redis_url, port=int(redis_port), db=0)