diff --git a/src/ad_seller/services/catalog_service.py b/src/ad_seller/services/catalog_service.py index 06a80c3..c6dd60d 100644 --- a/src/ad_seller/services/catalog_service.py +++ b/src/ad_seller/services/catalog_service.py @@ -392,11 +392,15 @@ def build_static_product_catalog() -> dict[str, Any]: """Build a fresh catalog dict from ``DEFAULT_PRODUCT_CONFIGS`` (uncached). Returns ``{"products": {product_id: ProductDefinition}, "inventory_types": [...]}`` - with newly generated product IDs. + with deterministic product IDs derived from each config's name, so every + process (and every uvicorn worker) serves the same ids. Random per-process + ids meant a list-then-get across two workers, or across a restart, could + 404 on an id the server itself had just returned (issue #34). """ products: dict[str, Any] = {} for cfg in DEFAULT_PRODUCT_CONFIGS: - product_def = product_from_config(cfg, f"prod-{uuid.uuid4().hex[:8]}") + stable = uuid.uuid5(uuid.NAMESPACE_URL, f"ad-seller-product:{cfg['name']}") + product_def = product_from_config(cfg, f"prod-{stable.hex[:8]}") products[product_def.product_id] = product_def inventory_types = sorted({p.inventory_type for p in products.values()}) diff --git a/tests/unit/test_csv_catalog_coherence.py b/tests/unit/test_csv_catalog_coherence.py index 3a5aa5b..53fed0c 100644 --- a/tests/unit/test_csv_catalog_coherence.py +++ b/tests/unit/test_csv_catalog_coherence.py @@ -215,6 +215,16 @@ def test_default_mode_ids_stay_uuid_shaped_and_stable(self, default_mode): second = catalog_service.get_static_product_catalog() assert list(first["products"].keys()) == list(second["products"].keys()) + def test_default_mode_ids_survive_cache_reset(self, default_mode): + # Proxy for multi-worker and restart behavior (issue #34): each uvicorn + # worker builds its own catalog cache, so ids must be deterministic + # across independent builds, not merely stable within one cache. + first = catalog_service.get_static_product_catalog() + catalog_service.reset_catalog_cache() + second = catalog_service.get_static_product_catalog() + assert list(first["products"].keys()) == list(second["products"].keys()) + assert len(set(first["products"])) == len(catalog_service.DEFAULT_PRODUCT_CONFIGS) + # ============================================================================= # API surface — CSV mode