Skip to content

Commit cf21bea

Browse files
committed
Derive default-catalog product ids deterministically (issue #34)
build_static_product_catalog minted prod-{uuid4} ids per process, so any multi-worker deployment (the shipped Dockerfile runs uvicorn --workers 2) or a restart between GET /products and GET /products/{id} could 404 on an id the server itself had just returned. This is the surviving kernel of issue #34 observation 1; the CSV-mode side was fixed in v2.2.2. Derive ids with uuid5 over the config name instead: same prod-[0-9a-f]{8} shape, unique per product, identical in every process. Adds a regression test that rebuilds the catalog after a cache reset (the single-process proxy for a second worker) and asserts the id set is unchanged.
1 parent 62803d4 commit cf21bea

2 files changed

Lines changed: 16 additions & 2 deletions

File tree

src/ad_seller/services/catalog_service.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,15 @@ def build_static_product_catalog() -> dict[str, Any]:
392392
"""Build a fresh catalog dict from ``DEFAULT_PRODUCT_CONFIGS`` (uncached).
393393
394394
Returns ``{"products": {product_id: ProductDefinition}, "inventory_types": [...]}``
395-
with newly generated product IDs.
395+
with deterministic product IDs derived from each config's name, so every
396+
process (and every uvicorn worker) serves the same ids. Random per-process
397+
ids meant a list-then-get across two workers, or across a restart, could
398+
404 on an id the server itself had just returned (issue #34).
396399
"""
397400
products: dict[str, Any] = {}
398401
for cfg in DEFAULT_PRODUCT_CONFIGS:
399-
product_def = product_from_config(cfg, f"prod-{uuid.uuid4().hex[:8]}")
402+
stable = uuid.uuid5(uuid.NAMESPACE_URL, f"ad-seller-product:{cfg['name']}")
403+
product_def = product_from_config(cfg, f"prod-{stable.hex[:8]}")
400404
products[product_def.product_id] = product_def
401405

402406
inventory_types = sorted({p.inventory_type for p in products.values()})

tests/unit/test_csv_catalog_coherence.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,16 @@ def test_default_mode_ids_stay_uuid_shaped_and_stable(self, default_mode):
215215
second = catalog_service.get_static_product_catalog()
216216
assert list(first["products"].keys()) == list(second["products"].keys())
217217

218+
def test_default_mode_ids_survive_cache_reset(self, default_mode):
219+
# Proxy for multi-worker and restart behavior (issue #34): each uvicorn
220+
# worker builds its own catalog cache, so ids must be deterministic
221+
# across independent builds, not merely stable within one cache.
222+
first = catalog_service.get_static_product_catalog()
223+
catalog_service.reset_catalog_cache()
224+
second = catalog_service.get_static_product_catalog()
225+
assert list(first["products"].keys()) == list(second["products"].keys())
226+
assert len(set(first["products"])) == len(catalog_service.DEFAULT_PRODUCT_CONFIGS)
227+
218228

219229
# =============================================================================
220230
# API surface — CSV mode

0 commit comments

Comments
 (0)