patx/veela

Sync source comments and clarify worker documentation

Commit 21e6819 · patx · 2026-10-13T23:17:57-04:00

Changeset
21e6819d06ac0101221d2779c3e1229beb26273a
Parents
a7cc9d7cfed5e3b7548c7773719009272b31d267

View source at this commit

Comments

No comments yet.

Log in to comment

Diff

diff --git a/README.md b/README.md
index 118e1c3..86410f6 100644
--- a/README.md
+++ b/README.md
@@ -154,11 +154,17 @@ Four workers. One file. Please allow the procurement department a moment.
 The default is `127.0.0.1:8000` with one worker. No
 `if __name__ == '__main__':` guard is needed, including with multiple workers.
 An existing guard around `app.run()` is fine too. Multiple workers need an app
-defined at module level outside that guard, and a Python script or importable
-module (not a REPL or `python -c`). Start them from the main thread.
-Workers re-execute application setup and have separate memory.
+defined at module level: put `app = App()` and your route registrations directly
+in the file, outside functions and the main guard, as in the example above.
+Each worker loads that named app in its own process, re-executes application
+setup, and has separate memory.
+
+`workers` must be a positive integer. Start multiple workers from the main
+thread using a Python script or `python -m your_module` (including packages),
+not a REPL or `python -c`.
 Ctrl+C and SIGTERM stop the server, join workers, and remove the temporary
 server archive before `run()` returns.
+
 The bundled server uses asyncio and h11, with WebSockets and lifespan disabled.
 `app.run()` also needs `uvicorn`, `h11`, and `click` not to be imported already.
 The magic prefers to make its own introductions.
diff --git a/source/wred.py b/source/wred.py
index e2507de..e2a1c61 100644
--- a/source/wred.py
+++ b/source/wred.py
@@ -114,9 +114,6 @@ class App:
         import threading
         from functools import partial
 
-        # Spawn re-executes the entry module before loading the worker target.
-        # Python exposes no public bootstrap-state check; this is the same flag
-        # multiprocessing uses to detect an unsafe recursive start.
         if _loading_worker_app or getattr(multiprocessing.current_process(), '_inheriting', False):
             return
         if type(workers) is not int or workers < 1:
@@ -133,7 +130,6 @@ class App:
             if module == '__main__':
                 spec = namespace.get('__spec__')
                 if spec is not None and spec.name.endswith('.__main__'):
-                    # multiprocessing does not re-execute package __main__ modules.
                     module = spec.name
                 elif not Path(namespace.get('__file__', '')).is_file():
                     raise ValueError('Multiple workers require a Python script or importable module')
@@ -167,7 +163,6 @@ class App:
                             try:
                                 supervisor.run()
                             except BaseException:
-                                # Uvicorn's supervisor does not clean up a partial start.
                                 supervisor.terminate_all()
                                 supervisor.join_all()
                                 raise
@@ -184,7 +179,6 @@ class App:
                         if path == archive or path.startswith((archive + '/', archive + '\\')):
                             del sys.path_importer_cache[path]
         except KeyboardInterrupt:
-            # Also cover Ctrl+C during imports and startup, before Uvicorn owns it.
             pass
         finally:
             for sig, handler in handlers.items():
diff --git a/wred.py b/wred.py
index 745b620..20ebfac 100644
--- a/wred.py
+++ b/wred.py
@@ -114,9 +114,6 @@ class App:
         import threading
         from functools import partial
 
-        # Spawn re-executes the entry module before loading the worker target.
-        # Python exposes no public bootstrap-state check; this is the same flag
-        # multiprocessing uses to detect an unsafe recursive start.
         if _loading_worker_app or getattr(multiprocessing.current_process(), '_inheriting', False):
             return
         if type(workers) is not int or workers < 1:
@@ -133,7 +130,6 @@ class App:
             if module == '__main__':
                 spec = namespace.get('__spec__')
                 if spec is not None and spec.name.endswith('.__main__'):
-                    # multiprocessing does not re-execute package __main__ modules.
                     module = spec.name
                 elif not Path(namespace.get('__file__', '')).is_file():
                     raise ValueError('Multiple workers require a Python script or importable module')
@@ -167,7 +163,6 @@ class App:
                             try:
                                 supervisor.run()
                             except BaseException:
-                                # Uvicorn's supervisor does not clean up a partial start.
                                 supervisor.terminate_all()
                                 supervisor.join_all()
                                 raise
@@ -184,7 +179,6 @@ class App:
                         if path == archive or path.startswith((archive + '/', archive + '\\')):
                             del sys.path_importer_cache[path]
         except KeyboardInterrupt:
-            # Also cover Ctrl+C during imports and startup, before Uvicorn owns it.
             pass
         finally:
             for sig, handler in handlers.items():