diff --git a/lightly_studio/Makefile b/lightly_studio/Makefile index f0b411fcc..96bbc712b 100644 --- a/lightly_studio/Makefile +++ b/lightly_studio/Makefile @@ -40,6 +40,11 @@ start-e2e: build @echo "Starting server for e2e tests..." uv run e2e-tests/index_dataset_for_end2end_ui_tests.py +.PHONY: start-coco-10k +start-coco-10k: build + @echo "Starting server for e2e tests with COCO 10k dataset..." + uv run e2e-tests/index_coco_10k.py + .PHONY: start-e2e-with-captions start-e2e-with-captions: build @echo "Starting server for e2e tests with captions..." diff --git a/lightly_studio/e2e-tests/index_coco_10k.py b/lightly_studio/e2e-tests/index_coco_10k.py new file mode 100644 index 000000000..3cd5c8202 --- /dev/null +++ b/lightly_studio/e2e-tests/index_coco_10k.py @@ -0,0 +1,25 @@ +"""End-to-end demonstration of the lightly_studio dataset loading and UI. + +This module provides a simple example of how to load a COCO instance +segmentation dataset and launch the UI application for exploration and +visualization. +""" + +from lightly_studio import AnnotationType, Dataset, db_manager, start_gui + +# Clean up an existing database +db_manager.connect(cleanup_existing=True) + +# Create a Dataset instance +dataset = Dataset.create() + +# We point to the annotations json file and the input images folder. +# Defined dataset is processed here to be available for the UI application. +dataset.add_samples_from_coco( + annotations_json="datasets/coco-10k/annotations/instances_train2017.json", + images_path="datasets/coco-10k/images", + annotation_type=AnnotationType.INSTANCE_SEGMENTATION, +) + +# We start the UI application on port 8001 +start_gui() diff --git a/lightly_studio/src/lightly_studio/api/server.py b/lightly_studio/src/lightly_studio/api/server.py index 1dd7c4d00..1ff6e4e69 100644 --- a/lightly_studio/src/lightly_studio/api/server.py +++ b/lightly_studio/src/lightly_studio/api/server.py @@ -30,8 +30,17 @@ def __init__(self, host: str, port: int) -> None: def start(self) -> None: """Start the API server using Uvicorn.""" - # start the app - uvicorn.run(app, host=self.host, port=self.port, http="h11") + # start the app with connection limits and timeouts + uvicorn.run( + app, + host=self.host, + port=self.port, + http="h11", + limit_concurrency=1000, # Max concurrent connections + limit_max_requests=10000, # Max requests before worker restart + timeout_keep_alive=5, # Keep-alive timeout in seconds + timeout_graceful_shutdown=30, # Graceful shutdown timeout + ) def _get_available_port(host: str, preferred_port: int, max_tries: int = 50) -> int: diff --git a/lightly_studio/src/lightly_studio/db_manager.py b/lightly_studio/src/lightly_studio/db_manager.py index 2a2152d2b..74f30e06e 100644 --- a/lightly_studio/src/lightly_studio/db_manager.py +++ b/lightly_studio/src/lightly_studio/db_manager.py @@ -41,7 +41,14 @@ def __init__( self._engine_url = engine_url if engine_url else "duckdb:///lightly_studio.db" if cleanup_existing: _cleanup_database_file(engine_url=self._engine_url) - self._engine = create_engine(url=self._engine_url, poolclass=poolclass) + # Total available connections = pool_size + max_overflow = 20 + 40 = 60 + # (default is (pool_size=5, max_overflow=10)) + self._engine = create_engine( + url=self._engine_url, + poolclass=poolclass, + pool_size=20, + max_overflow=40, + ) SQLModel.metadata.create_all(self._engine) @contextmanager diff --git a/lightly_studio_view/src/lib/components/Samples/Samples.svelte b/lightly_studio_view/src/lib/components/Samples/Samples.svelte index 8256928c6..303f3fecf 100644 --- a/lightly_studio_view/src/lib/components/Samples/Samples.svelte +++ b/lightly_studio_view/src/lib/components/Samples/Samples.svelte @@ -241,7 +241,7 @@ {:else if $infiniteSamples.isSuccess && samples.length === 0}