diff --git a/app/resolve/scene_resolver.py b/app/resolve/scene_resolver.py index a5a008b..282eef3 100644 --- a/app/resolve/scene_resolver.py +++ b/app/resolve/scene_resolver.py @@ -584,18 +584,24 @@ def _sync_tags( norm: NormalizedScene, source_id: uuid.UUID, ) -> None: + # PostgreSQL INSERT ... ON CONFLICT DO NOTHING — race-safe. Wcześniejsze + # check-then-insert ścigało się przy równoległym ingescie tej samej sceny + # (dwa runy widziały existing=None → oba add → IntegrityError pk_scene_tags, + # GOON-M). Analogicznie do movie_resolver._sync_tags. + from sqlalchemy.dialects.postgresql import insert as pg_insert + + seen_tag_ids: set[uuid.UUID] = set() for t_norm in norm.tags: tag = resolve_tag(session, norm=t_norm) - if tag is None: + if tag is None or tag.id in seen_tag_ids: continue - existing = session.execute( - select(SceneTag).where( - SceneTag.scene_id == scene_id, - SceneTag.tag_id == tag.id, - ) - ).scalar_one_or_none() - if existing is None: - session.add(SceneTag(scene_id=scene_id, tag_id=tag.id, source_id=source_id)) + seen_tag_ids.add(tag.id) + stmt = ( + pg_insert(SceneTag.__table__) + .values(scene_id=scene_id, tag_id=tag.id, source_id=source_id) + .on_conflict_do_nothing(index_elements=["scene_id", "tag_id"]) + ) + session.execute(stmt) def _sync_fingerprints(