add command-line options for Uvicorn server configuration

This commit is contained in:
kstyagi23
2026-09-05 06:15:18 +05:30
parent c4facda5ce
commit 48402f7d61
3 changed files with 83 additions and 5 deletions
+14 -3
View File
@@ -41,10 +41,21 @@ siteharbor
Open `http://127.0.0.1:8787`.
The `siteharbor` command runs the FastAPI application with Uvicorn. Override the bind port and
start multiple Uvicorn worker processes when needed:
```powershell
siteharbor --port 9000 --workers 2
```
`--port` accepts ports from 1 through 65535 and overrides `SITEHARBOR_PORT`. `--workers` defaults
to 1 and controls Uvicorn processes, not the capture-worker count configured by
`SITEHARBOR_WORKER_CONCURRENCY`.
To use Uvicorn directly:
```powershell
python -m uvicorn app.main:app --host 127.0.0.1 --port 8787
python -m uvicorn app.main:app --host 127.0.0.1 --port 8787 --workers 2
```
The default bind address is loopback. Do not expose SiteHarbor directly to the public Internet without authentication, a network egress policy, rate limits, and operational controls.
@@ -56,9 +67,9 @@ All configuration uses environment variables prefixed with `SITEHARBOR_`.
| Variable | Default | Purpose |
| --- | --- | --- |
| `SITEHARBOR_HOST` | `127.0.0.1` | Bind address used by `siteharbor`. |
| `SITEHARBOR_PORT` | `8787` | Bind port used by `siteharbor`. |
| `SITEHARBOR_PORT` | `8787` | Default bind port used by `siteharbor`; overridden by `--port`. |
| `SITEHARBOR_DATA_DIR` | `./data` | SQLite database, work directories, artifacts, and reports. |
| `SITEHARBOR_WORKER_CONCURRENCY` | `1` | Capture workers per application process. |
| `SITEHARBOR_WORKER_CONCURRENCY` | `1` | Capture workers per Uvicorn process; separate from `--workers`. |
| `SITEHARBOR_FETCH_CONCURRENCY` | `6` | Maximum parallel fetches a visitor may select for one capture. |
| `SITEHARBOR_LEASE_SECONDS` | `120` | SQLite worker lease duration; values below 15 seconds are rejected. |
| `SITEHARBOR_ALLOW_PRIVATE_NETWORKS` | `false` | Development-only override that permits loopback and private hosts. |
+46 -2
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import argparse
import asyncio
import json
import re
@@ -387,8 +388,51 @@ def _safe_data_file(path_value: str, root: Path) -> Path | None:
return None
def run() -> None:
uvicorn.run("app.main:app", host=settings.host, port=settings.port, reload=False)
def _positive_integer(value: str) -> int:
try:
number = int(value)
except ValueError as error:
raise argparse.ArgumentTypeError("must be a whole number") from error
if number < 1:
raise argparse.ArgumentTypeError("must be at least 1")
return number
def _port_number(value: str) -> int:
port = _positive_integer(value)
if port > 65_535:
raise argparse.ArgumentTypeError("must be between 1 and 65535")
return port
def _parse_server_arguments(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Run the SiteHarbor FastAPI server with Uvicorn.")
parser.add_argument(
"--port",
type=_port_number,
default=settings.port,
metavar="PORT",
help=f"bind port (default: SITEHARBOR_PORT or {settings.port})",
)
parser.add_argument(
"--workers",
type=_positive_integer,
default=1,
metavar="WORKERS",
help="number of Uvicorn worker processes (default: 1)",
)
return parser.parse_args(argv)
def run(argv: list[str] | None = None) -> None:
arguments = _parse_server_arguments(argv)
uvicorn.run(
"app.main:app",
host=settings.host,
port=arguments.port,
workers=arguments.workers,
reload=False,
)
if __name__ == "__main__":
+23
View File
@@ -65,3 +65,26 @@ def test_capture_routes_are_scoped_to_the_browser_session(tmp_path, monkeypatch)
stats = client.get("/api/stats")
assert stats.status_code == 200
assert stats.json()["active_crawls"] == 1
def test_run_forwards_server_options_to_uvicorn(monkeypatch) -> None:
calls: list[tuple[tuple[object, ...], dict[str, object]]] = []
def fake_run(*args: object, **kwargs: object) -> None:
calls.append((args, kwargs))
monkeypatch.setattr(main.uvicorn, "run", fake_run)
main.run(["--port", "9123", "--workers", "2"])
assert calls == [
(
("app.main:app",),
{
"host": settings.host,
"port": 9123,
"workers": 2,
"reload": False,
},
)
]