amfs-http-server 0.3.40__tar.gz → 0.3.41__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/PKG-INFO +2 -2
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/pyproject.toml +5 -2
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/server.py +30 -1
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/.gitignore +0 -0
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/__init__.py +0 -0
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/auth.py +0 -0
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/models.py +0 -0
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/openrouter_proxy.py +0 -0
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/pro_provider.py +0 -0
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/pro_proxy.py +0 -0
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/sse.py +0 -0
- {amfs_http_server-0.3.40 → amfs_http_server-0.3.41}/src/amfs_http/tenant_middleware.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: amfs-http-server
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.41
|
|
4
4
|
Summary: AMFS HTTP/REST API server with SSE support
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -9,6 +9,6 @@ Requires-Dist: amfs>=0.5.27
|
|
|
9
9
|
Requires-Dist: fastapi>=0.115
|
|
10
10
|
Requires-Dist: httpx>=0.27
|
|
11
11
|
Requires-Dist: sse-starlette>=2.0
|
|
12
|
-
Requires-Dist: uvicorn[standard]>=0.
|
|
12
|
+
Requires-Dist: uvicorn[standard]>=0.37
|
|
13
13
|
Provides-Extra: pro
|
|
14
14
|
Requires-Dist: amfs-patterns; extra == 'pro'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "amfs-http-server"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.41"
|
|
4
4
|
description = "AMFS HTTP/REST API server with SSE support"
|
|
5
5
|
requires-python = ">=3.11"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -29,7 +29,10 @@ dependencies = [
|
|
|
29
29
|
# agent's private keys. Either way the floor is what makes the rule real.
|
|
30
30
|
"amfs-core>=0.3.37",
|
|
31
31
|
"fastapi>=0.115",
|
|
32
|
-
|
|
32
|
+
# 0.37 is where uvicorn.run() grew timeout_worker_healthcheck, which
|
|
33
|
+
# main() passes unconditionally; on anything older that is a TypeError
|
|
34
|
+
# before the first socket is bound, one worker or twenty.
|
|
35
|
+
"uvicorn[standard]>=0.37",
|
|
33
36
|
"sse-starlette>=2.0",
|
|
34
37
|
"httpx>=0.27",
|
|
35
38
|
]
|
|
@@ -8826,6 +8826,23 @@ async def ingest_event(
|
|
|
8826
8826
|
# CLI Entry Point
|
|
8827
8827
|
# ──────────────────────────────────────────────────────────────────────
|
|
8828
8828
|
|
|
8829
|
+
# With more than one worker, uvicorn runs a supervisor that pings every worker
|
|
8830
|
+
# twice a second and SIGKILLs any that has not answered within
|
|
8831
|
+
# ``timeout_worker_healthcheck`` — 5 seconds by default — then spawns a fresh
|
|
8832
|
+
# one and logs the same "Child process [pid] died" it would for a real crash.
|
|
8833
|
+
# The pong comes from a thread the worker starts on entry, so it needs the GIL,
|
|
8834
|
+
# and a fresh worker does not have one to give: spawn re-imports this module
|
|
8835
|
+
# and its C extensions and the lifespan loads the embedding models, all of it
|
|
8836
|
+
# CPU-bound, all of it competing with the worker next door that is serving
|
|
8837
|
+
# traffic. On a 2-vCPU Cloud Run instance that reliably took longer than 5
|
|
8838
|
+
# seconds, so one slot per instance was killed every 8 seconds forever and
|
|
8839
|
+
# never once logged "Started server process" (2026-09-21, 36 kills a minute
|
|
8840
|
+
# across the fleet, every request that landed on the dying slot truncated).
|
|
8841
|
+
# Two minutes is generous room to start and rides out any GIL hold a request
|
|
8842
|
+
# could plausibly cause, while a worker that is genuinely wedged still gets
|
|
8843
|
+
# replaced. A single worker has no supervisor and is unaffected either way.
|
|
8844
|
+
DEFAULT_WORKER_HEALTHCHECK_S = 120
|
|
8845
|
+
|
|
8829
8846
|
|
|
8830
8847
|
def _parse_args() -> argparse.Namespace:
|
|
8831
8848
|
parser = argparse.ArgumentParser(
|
|
@@ -8862,6 +8879,16 @@ def _parse_args() -> argparse.Namespace:
|
|
|
8862
8879
|
default=int(os.environ.get("AMFS_HTTP_WORKERS", "1")),
|
|
8863
8880
|
help="Number of uvicorn worker processes (default: 1, env: AMFS_HTTP_WORKERS)",
|
|
8864
8881
|
)
|
|
8882
|
+
parser.add_argument(
|
|
8883
|
+
"--worker-healthcheck-timeout",
|
|
8884
|
+
type=int,
|
|
8885
|
+
default=int(os.environ.get("AMFS_HTTP_WORKER_HEALTHCHECK_S", str(DEFAULT_WORKER_HEALTHCHECK_S))),
|
|
8886
|
+
help=(
|
|
8887
|
+
"Seconds a worker may go without answering the supervisor's ping before "
|
|
8888
|
+
"it is killed and replaced; only meaningful with --workers > 1 "
|
|
8889
|
+
f"(default: {DEFAULT_WORKER_HEALTHCHECK_S}, env: AMFS_HTTP_WORKER_HEALTHCHECK_S)"
|
|
8890
|
+
),
|
|
8891
|
+
)
|
|
8865
8892
|
return parser.parse_args()
|
|
8866
8893
|
|
|
8867
8894
|
|
|
@@ -8998,7 +9025,8 @@ def main() -> None:
|
|
|
8998
9025
|
workers = 1
|
|
8999
9026
|
|
|
9000
9027
|
logger.info(
|
|
9001
|
-
"Starting AMFS HTTP server on %s:%d (workers=%d
|
|
9028
|
+
"Starting AMFS HTTP server on %s:%d (workers=%d, worker healthcheck=%ds)",
|
|
9029
|
+
args.host, args.port, workers, args.worker_healthcheck_timeout,
|
|
9002
9030
|
)
|
|
9003
9031
|
uvicorn.run(
|
|
9004
9032
|
"amfs_http.server:app",
|
|
@@ -9006,6 +9034,7 @@ def main() -> None:
|
|
|
9006
9034
|
port=args.port,
|
|
9007
9035
|
reload=args.reload,
|
|
9008
9036
|
workers=workers,
|
|
9037
|
+
timeout_worker_healthcheck=args.worker_healthcheck_timeout,
|
|
9009
9038
|
)
|
|
9010
9039
|
|
|
9011
9040
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|