Public Access
feat: run matcher after successful scrape; failures don't flip scrape status
This commit is contained in:
@@ -86,6 +86,12 @@ def _run_scrape_in_background(
|
|||||||
log.duration_seconds = int(
|
log.duration_seconds = int(
|
||||||
(log.completed_at - log.started_at).total_seconds()
|
(log.completed_at - log.started_at).total_seconds()
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
|
from app.services.matcher import run_match_job
|
||||||
|
run_match_job(db, source_filter="lucky_california")
|
||||||
|
except Exception as e: # matcher failure must not flip scrape to FAILED
|
||||||
|
import logging
|
||||||
|
logging.exception("matcher failed after successful scrape: %s", e)
|
||||||
db.commit()
|
db.commit()
|
||||||
logger.info(
|
logger.info(
|
||||||
"Background scrape %s complete: %s/%s items saved",
|
"Background scrape %s complete: %s/%s items saved",
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.requires_postgres
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_match_job_persists_top_matches(monkeypatch):
|
||||||
|
"""End-to-end: seed Ingredient + GroceryItem rows, run the matcher,
|
||||||
|
verify ingredient_grocery_match rows exist with confidence >= 0.75.
|
||||||
|
"""
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from decimal import Decimal
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from app.database import SessionLocal
|
||||||
|
from app.models import (
|
||||||
|
GroceryItem,
|
||||||
|
Ingredient,
|
||||||
|
IngredientGroceryMatch,
|
||||||
|
IngredientMatchSource,
|
||||||
|
)
|
||||||
|
from app.services.matcher import run_match_job
|
||||||
|
|
||||||
|
setup = SessionLocal()
|
||||||
|
ing_id = uuid4()
|
||||||
|
grocery_id = uuid4()
|
||||||
|
try:
|
||||||
|
setup.add(
|
||||||
|
Ingredient(
|
||||||
|
id=ing_id,
|
||||||
|
name="Zorblax Fizzberry Test",
|
||||||
|
name_lower="zorblax fizzberry test",
|
||||||
|
aliases=["zorblax fizzberry"],
|
||||||
|
aisle="meat",
|
||||||
|
unit="lb",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
setup.add(
|
||||||
|
GroceryItem(
|
||||||
|
id=grocery_id,
|
||||||
|
name="Zorblax Fizzberry Family Pack",
|
||||||
|
source="lucky_california",
|
||||||
|
external_id="ext-test-1",
|
||||||
|
current_price=Decimal("3.99"),
|
||||||
|
regular_price=Decimal("5.49"),
|
||||||
|
is_on_sale=True,
|
||||||
|
scraped_at=datetime.now(timezone.utc),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
setup.commit()
|
||||||
|
finally:
|
||||||
|
setup.close()
|
||||||
|
|
||||||
|
work = SessionLocal()
|
||||||
|
try:
|
||||||
|
written = run_match_job(work)
|
||||||
|
assert written >= 1
|
||||||
|
rows = (
|
||||||
|
work.query(IngredientGroceryMatch)
|
||||||
|
.filter(IngredientGroceryMatch.ingredient_id == ing_id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
assert any(
|
||||||
|
r.grocery_item_id == grocery_id
|
||||||
|
and r.confidence >= Decimal("0.750")
|
||||||
|
and r.source == IngredientMatchSource.AUTO
|
||||||
|
for r in rows
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
cleanup = SessionLocal()
|
||||||
|
try:
|
||||||
|
cleanup.query(IngredientGroceryMatch).filter(
|
||||||
|
IngredientGroceryMatch.ingredient_id == ing_id
|
||||||
|
).delete()
|
||||||
|
cleanup.query(GroceryItem).filter(GroceryItem.id == grocery_id).delete()
|
||||||
|
cleanup.query(Ingredient).filter(Ingredient.id == ing_id).delete()
|
||||||
|
cleanup.commit()
|
||||||
|
finally:
|
||||||
|
cleanup.close()
|
||||||
|
work.close()
|
||||||
Reference in New Issue
Block a user