Perf: serve stacks list from one Docker call; registry host → 10.10.6.10 (0.21.6)
Stacks overview and detail were doing an N+1 inspect storm: list_stacks called containers_for_stack AND compute_status (which re-fetched) per stack, and containers.list(sparse=False) full-inspects every container plus c.image triggered an image-inspect each. For N stacks that was ~2N*(1 list + M inspects + M image-inspects) sequential socket round trips (~1s for just 2 stacks, growing linearly). - compose_service.stack_status_summaries(): one low-level api.containers(all=True) summary call grouped by compose project label → whole list served in a single Docker round-trip (~10x faster). - compute_status() takes optional pre-fetched containers; get_stack and _stack_summary no longer double-fetch. - containers_for_stack() reads the image name from the inspect it already has instead of c.image (drops the per-container image-inspect). - Same batching applied to the agent's stack list/detail. Also: Forgejo (registry + git) moved to 10.10.6.10:3020 — updated image refs in docker-compose.yml, agent/Dockerfile, agent/docker-compose.yml. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cf046648bd
commit
5b59f5e8f9
+29
-13
@@ -62,7 +62,7 @@ def _map_docker(exc: DockerError):
|
||||
raise HTTPException(status_code=code, detail=exc.detail or exc.error)
|
||||
raise exc # falls through to the global 502 DockerError handler
|
||||
|
||||
AGENT_VERSION = "0.21.5"
|
||||
AGENT_VERSION = "0.21.6"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
@@ -137,20 +137,31 @@ def _file_guard(fn, *args, **kwargs):
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
def _summary(stack_id: str) -> dict:
|
||||
try:
|
||||
containers = compose_service.containers_for_stack(stack_id)
|
||||
status = compose_service.compute_status(stack_id)
|
||||
except DockerError:
|
||||
containers = []
|
||||
status = "unknown"
|
||||
def _summary(stack_id: str, summaries: dict | None = None) -> dict:
|
||||
if summaries is None:
|
||||
try:
|
||||
containers = compose_service.containers_for_stack(stack_id)
|
||||
total = len(containers)
|
||||
running = sum(1 for c in containers if c.state == "running")
|
||||
status = compose_service.compute_status(stack_id, containers)
|
||||
except DockerError:
|
||||
total = running = 0
|
||||
status = "unknown"
|
||||
else:
|
||||
info = summaries.get(stack_id)
|
||||
total = info["total"] if info else 0
|
||||
running = info["running"] if info else 0
|
||||
if compose_service.is_busy(stack_id):
|
||||
status = "updating"
|
||||
else:
|
||||
status = info["status"] if info else "stopped"
|
||||
return {
|
||||
"id": stack_id,
|
||||
"name": stack_id,
|
||||
"description": None,
|
||||
"status": status,
|
||||
"service_count": len(containers),
|
||||
"running_count": sum(1 for c in containers if c.state == "running"),
|
||||
"service_count": total,
|
||||
"running_count": running,
|
||||
"created_at": None,
|
||||
"updated_at": None,
|
||||
}
|
||||
@@ -245,7 +256,11 @@ def system() -> dict:
|
||||
|
||||
@app.get("/agent/stacks", dependencies=[Depends(verify_token)])
|
||||
def list_stacks() -> list[dict]:
|
||||
return [_summary(sid) for sid in compose_service.discover_stacks()]
|
||||
try:
|
||||
summaries = compose_service.stack_status_summaries()
|
||||
except DockerError:
|
||||
summaries = {}
|
||||
return [_summary(sid, summaries) for sid in compose_service.discover_stacks()]
|
||||
|
||||
|
||||
@app.get("/agent/stacks/stats", dependencies=[Depends(verify_token)])
|
||||
@@ -259,8 +274,9 @@ def get_stack(stack_id: str) -> dict:
|
||||
if not os.path.isdir(directory):
|
||||
raise HTTPException(status_code=404, detail=f"Stack '{stack_id}' not found")
|
||||
try:
|
||||
containers = [asdict(c) for c in compose_service.containers_for_stack(stack_id)]
|
||||
status = compose_service.compute_status(stack_id)
|
||||
raw = compose_service.containers_for_stack(stack_id)
|
||||
containers = [asdict(c) for c in raw]
|
||||
status = compose_service.compute_status(stack_id, raw)
|
||||
except DockerError:
|
||||
containers = []
|
||||
status = "unknown"
|
||||
|
||||
Reference in New Issue
Block a user