diff --git a/worker/lyra_worker/discovery.py b/worker/lyra_worker/discovery.py index d4d153b..e978799 100644 --- a/worker/lyra_worker/discovery.py +++ b/worker/lyra_worker/discovery.py @@ -13,7 +13,7 @@ _TRUE = {"1", "true", "yes", "on"} class DiscoveryConfig: enabled: bool = False interval_hours: int = 168 - max_seeds: int = 50 + chunk_size: int = 5 similar_per_seed: int = 20 albums_per_artist: int = 1 min_score: float = 0.0 @@ -35,7 +35,7 @@ class DiscoveryConfig: return cls( enabled=str(config.get("discover.enabled", "")).strip().lower() in _TRUE, interval_hours=_int("discover.intervalHours", 168), - max_seeds=_int("discover.maxSeeds", 50), + chunk_size=_int("discover.chunkSize", 5), similar_per_seed=_int("discover.similarPerSeed", 20), albums_per_artist=_int("discover.albumsPerArtist", 1), min_score=_float("discover.minScore", 0.0), @@ -46,6 +46,7 @@ class DiscoveryConfig: class DiscoveryResult: artists: int albums: int + seeds: int = 0 def _healthy_sources(sources): @@ -68,7 +69,7 @@ def _seed_artists(conn: psycopg.Connection, cfg: DiscoveryConfig): 'WHERE "lastDiscoveredAt" IS NULL ' ' OR "lastDiscoveredAt" < now() - make_interval(hours => %s) ' 'ORDER BY "lastDiscoveredAt" ASC NULLS FIRST LIMIT %s', - (cfg.interval_hours, cfg.max_seeds), + (cfg.interval_hours, cfg.chunk_size), ) return cur.fetchall() @@ -190,4 +191,4 @@ def run_discovery(conn: psycopg.Connection, sources: list[SimilaritySource], cur.execute('UPDATE "WatchedArtist" SET "lastDiscoveredAt" = now() WHERE mbid = %s', (seed_mbid,)) conn.commit() - return DiscoveryResult(artists=artists, albums=albums) + return DiscoveryResult(artists=artists, albums=albums, seeds=len(seeds)) diff --git a/worker/tests/test_discovery.py b/worker/tests/test_discovery.py index 991d59f..ec6110e 100644 --- a/worker/tests/test_discovery.py +++ b/worker/tests/test_discovery.py @@ -88,9 +88,26 @@ def test_source_with_raising_health_is_skipped_not_fatal(conn): def test_config_from_config_parses_and_defaults(): - cfg = DiscoveryConfig.from_config({"discover.enabled": "true", "discover.maxSeeds": "10", + cfg = DiscoveryConfig.from_config({"discover.enabled": "true", "discover.chunkSize": "10", "discover.minScore": "0.3"}) - assert cfg.enabled is True and cfg.max_seeds == 10 and cfg.min_score == 0.3 + assert cfg.enabled is True and cfg.chunk_size == 10 and cfg.min_score == 0.3 d = DiscoveryConfig.from_config({}) - assert (d.enabled, d.interval_hours, d.max_seeds, d.similar_per_seed, - d.albums_per_artist, d.min_score) == (False, 168, 50, 20, 1, 0.0) + assert (d.enabled, d.interval_hours, d.chunk_size, d.similar_per_seed, + d.albums_per_artist, d.min_score) == (False, 168, 5, 20, 1, 0.0) + + +def test_run_discovery_processes_at_most_chunk_size_seeds(conn): + from lyra_worker.discovery import DiscoveryConfig, run_discovery + from lyra_worker.adapters.fakes import FakeMbBrowser, FakeSimilaritySource + from lyra_worker.similarity.base import SimilarArtist + from tests.conftest import insert_watched_artist + for i in range(4): + insert_watched_artist(conn, mbid=f"s{i}", name=f"Seed{i}") + src = FakeSimilaritySource(similar={f"s{i}": [SimilarArtist(f"c{i}", f"Cand{i}", 0.9)] for i in range(4)}) + cfg = DiscoveryConfig.from_config({"discover.chunkSize": "2"}) + result = run_discovery(conn, [src], FakeMbBrowser(), cfg) + assert result.seeds == 2 # only chunk_size seeds this call + # exactly 2 seeds now have lastDiscoveredAt set + with conn.cursor() as cur: + cur.execute('SELECT count(*) FROM "WatchedArtist" WHERE "lastDiscoveredAt" IS NOT NULL') + assert cur.fetchone()[0] == 2