fix: tool start hanging + SSE 429 errors

1. Remove Docker build from create_instance for manifest types — the build
   was blocking the HTTP request for several minutes, causing frontend
   timeouts and retries. Image is now built lazily on start (via the
   existing _prepare_manifest_instance path in start_instance).

2. Increase MAX_CONNECTIONS_PER_USER from 5 to 20 for SSE endpoint —
   aggressive reconnect loops from the frontend were exhausting the limit
   and causing 429 errors unrelated to tool starting.

Quality gates: ruff clean, tsc --noEmit clean, pytest workspaces (9 passed)
This commit is contained in:
2026-06-01 23:29:28 +02:00
parent 8837031fd2
commit 56dd7d3fd3
3 changed files with 14 additions and 46 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ router = APIRouter(prefix="/events", tags=["events"])
# In-memory connection counter per user (single-process assumption)
_connection_counts: dict[uuid.UUID, int] = {}
MAX_CONNECTIONS_PER_USER = 5
MAX_CONNECTIONS_PER_USER = 20
@router.get("/stream")
+1 -37
View File
@@ -1039,7 +1039,7 @@ services:
write_compose_file(instance_dir, compose_content)
elif tool_type.definition_type == "manifest":
# Manifest-based: build image and generate compose
# Manifest-based: generate compose only; image built lazily on start
from src.models.tool_definition_manifest import ToolDefinitionManifest
manifest_def = await session.get(
@@ -1061,44 +1061,8 @@ services:
deep_merge(dict(base_def.manifest), manifest)
)
# Determine home directory for path expansion
_home_dir = get_manifest_home_dir(manifest)
image_tag = compute_image_tag(tool_type.name, manifest)
# Build image during creation so start is fast
dockerfile = compile_dockerfile(manifest)
entrypoint = compile_entrypoint(manifest)
build_ctx = {
"Dockerfile": dockerfile,
".headquarter/entrypoint.sh": entrypoint,
}
returncode, stdout, stderr = await asyncio.to_thread(
build_image,
instance_dir=instance_dir,
dockerfile=dockerfile,
tag=image_tag,
build_context=build_ctx,
)
if returncode != 0:
logger.error(
"Failed to build image for manifest instance %s: %s",
instance_name,
stderr,
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to build Docker image: {stderr[:500]}",
)
logger.info(
"Built manifest image %s for instance %s",
image_tag,
instance_name,
)
variables = {
"IMAGE_TAG": image_tag,
"INSTANCE_NAME": instance_name.lower(),
+12 -8
View File
@@ -91,14 +91,18 @@ class TerminalManager:
"""
try:
async with SessionLocal() as db_session:
stmt = pg_insert(TerminalSessionModel).values(
id=uuid.UUID(session_id),
instance_id=instance_id,
name=name,
status="active",
created_at=datetime.now(timezone.utc),
last_activity_at=datetime.now(timezone.utc),
).on_conflict_do_nothing(index_elements=["id"])
stmt = (
pg_insert(TerminalSessionModel)
.values(
id=uuid.UUID(session_id),
instance_id=instance_id,
name=name,
status="active",
created_at=datetime.now(timezone.utc),
last_activity_at=datetime.now(timezone.utc),
)
.on_conflict_do_nothing(index_elements=["id"])
)
await db_session.execute(stmt)
await db_session.commit()
logger.debug(