Skip to content

Commit

Permalink
Disable multiprocessing if number of workers is 0
Browse files Browse the repository at this point in the history
This should allow support of Digital Ocean and other hosting
environments that don't support multiprocessing. Note thought there is
no intention of supporting the reloader in this state (as pre 14.3).
  • Loading branch information
pgjones committed Oct 29, 2023
1 parent 30e6f03 commit 662ffa9
Showing 1 changed file with 46 additions and 40 deletions.
86 changes: 46 additions & 40 deletions src/hypercorn/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,50 +37,56 @@ def run(config: Config) -> None:

sockets = config.create_sockets()

if config.use_reloader:
if config.use_reloader and config.workers == 0:
raise RuntimeError("Cannot reload without workers")

if config.use_reloader or config.workers == 0:
# Load the application so that the correct paths are checked for
# changes, but only when the reloader is being used.
load_application(config.application_path, config.wsgi_max_body_size)

ctx = get_context("spawn")

active = True
while active:
# Ignore SIGINT before creating the processes, so that they
# inherit the signal handling. This means that the shutdown
# function controls the shutdown.
signal.signal(signal.SIGINT, signal.SIG_IGN)

shutdown_event = ctx.Event()
processes = start_processes(config, worker_func, sockets, shutdown_event, ctx)

def shutdown(*args: Any) -> None:
nonlocal active, shutdown_event
shutdown_event.set()
active = False

for signal_name in {"SIGINT", "SIGTERM", "SIGBREAK"}:
if hasattr(signal, signal_name):
signal.signal(getattr(signal, signal_name), shutdown)

if config.use_reloader:
wait_for_changes(shutdown_event)
shutdown_event.set()
# Recreate the sockets to be used again in the next
# iteration of the loop.
sockets = config.create_sockets()
else:
active = False

for process in processes:
process.join()
for process in processes:
process.terminate()

for sock in sockets.secure_sockets:
sock.close()
for sock in sockets.insecure_sockets:
sock.close()
if config.workers == 0:
worker_func(config, sockets)
else:
ctx = get_context("spawn")

active = True
while active:
# Ignore SIGINT before creating the processes, so that they
# inherit the signal handling. This means that the shutdown
# function controls the shutdown.
signal.signal(signal.SIGINT, signal.SIG_IGN)

shutdown_event = ctx.Event()
processes = start_processes(config, worker_func, sockets, shutdown_event, ctx)

def shutdown(*args: Any) -> None:
nonlocal active, shutdown_event
shutdown_event.set()
active = False

for signal_name in {"SIGINT", "SIGTERM", "SIGBREAK"}:
if hasattr(signal, signal_name):
signal.signal(getattr(signal, signal_name), shutdown)

if config.use_reloader:
wait_for_changes(shutdown_event)
shutdown_event.set()
# Recreate the sockets to be used again in the next
# iteration of the loop.
sockets = config.create_sockets()
else:
active = False

for process in processes:
process.join()
for process in processes:
process.terminate()

for sock in sockets.secure_sockets:
sock.close()
for sock in sockets.insecure_sockets:
sock.close()


def start_processes(
Expand Down

0 comments on commit 662ffa9

Please sign in to comment.