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:
@@ -16,7 +16,7 @@ router = APIRouter(prefix="/events", tags=["events"])
|
|||||||
|
|
||||||
# In-memory connection counter per user (single-process assumption)
|
# In-memory connection counter per user (single-process assumption)
|
||||||
_connection_counts: dict[uuid.UUID, int] = {}
|
_connection_counts: dict[uuid.UUID, int] = {}
|
||||||
MAX_CONNECTIONS_PER_USER = 5
|
MAX_CONNECTIONS_PER_USER = 20
|
||||||
|
|
||||||
|
|
||||||
@router.get("/stream")
|
@router.get("/stream")
|
||||||
|
|||||||
@@ -1039,7 +1039,7 @@ services:
|
|||||||
write_compose_file(instance_dir, compose_content)
|
write_compose_file(instance_dir, compose_content)
|
||||||
|
|
||||||
elif tool_type.definition_type == "manifest":
|
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
|
from src.models.tool_definition_manifest import ToolDefinitionManifest
|
||||||
|
|
||||||
manifest_def = await session.get(
|
manifest_def = await session.get(
|
||||||
@@ -1061,44 +1061,8 @@ services:
|
|||||||
deep_merge(dict(base_def.manifest), manifest)
|
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)
|
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 = {
|
variables = {
|
||||||
"IMAGE_TAG": image_tag,
|
"IMAGE_TAG": image_tag,
|
||||||
"INSTANCE_NAME": instance_name.lower(),
|
"INSTANCE_NAME": instance_name.lower(),
|
||||||
|
|||||||
@@ -91,14 +91,18 @@ class TerminalManager:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
async with SessionLocal() as db_session:
|
async with SessionLocal() as db_session:
|
||||||
stmt = pg_insert(TerminalSessionModel).values(
|
stmt = (
|
||||||
id=uuid.UUID(session_id),
|
pg_insert(TerminalSessionModel)
|
||||||
instance_id=instance_id,
|
.values(
|
||||||
name=name,
|
id=uuid.UUID(session_id),
|
||||||
status="active",
|
instance_id=instance_id,
|
||||||
created_at=datetime.now(timezone.utc),
|
name=name,
|
||||||
last_activity_at=datetime.now(timezone.utc),
|
status="active",
|
||||||
).on_conflict_do_nothing(index_elements=["id"])
|
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.execute(stmt)
|
||||||
await db_session.commit()
|
await db_session.commit()
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
|||||||
Reference in New Issue
Block a user