diff --git a/bp/blog/ghost/ghost_sync.py b/bp/blog/ghost/ghost_sync.py index 0e1d6ec..f9b8d76 100644 --- a/bp/blog/ghost/ghost_sync.py +++ b/bp/blog/ghost/ghost_sync.py @@ -214,23 +214,26 @@ async def _upsert_post(sess: AsyncSession, gp: Dict[str, Any], author_map: Dict[ res = await sess.execute(select(Post).where(Post.ghost_id == gp["id"])) obj = res.scalar_one_or_none() - if obj is None: - obj = Post(ghost_id=gp["id"]) # type: ignore[call-arg] - sess.add(obj) - _apply_ghost_fields(obj, gp, author_map, tag_map) - - try: - async with sess.begin_nested(): - await sess.flush() - except IntegrityError: - # Race condition: another request inserted this ghost_id concurrently. - # Expunge the failed object, re-select the existing row, and update it. - sess.expunge(obj) - res = await sess.execute(select(Post).where(Post.ghost_id == gp["id"])) - obj = res.scalar_one() + if obj is not None: + # Row exists — just update _apply_ghost_fields(obj, gp, author_map, tag_map) await sess.flush() + else: + # Row doesn't exist — try to insert within a savepoint + obj = Post(ghost_id=gp["id"]) # type: ignore[call-arg] + try: + async with sess.begin_nested(): + sess.add(obj) + _apply_ghost_fields(obj, gp, author_map, tag_map) + await sess.flush() + except IntegrityError: + # Race condition: another request inserted this ghost_id. + # Savepoint rolled back; re-select and update. + res = await sess.execute(select(Post).where(Post.ghost_id == gp["id"])) + obj = res.scalar_one() + _apply_ghost_fields(obj, gp, author_map, tag_map) + await sess.flush() # Backfill user_id from primary author email if not already set if obj.user_id is None and obj.primary_author_id is not None: