Fix page creation labels and webhook race condition
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 56s

- Updated shared submodule: page-aware blog_new template labels
- _upsert_post: handle concurrent webhook INSERTs via savepoint + retry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-21 22:32:05 +00:00
parent 954b6cc06a
commit 80e4f21b0b
2 changed files with 26 additions and 9 deletions

View File

@@ -164,13 +164,8 @@ async def _upsert_tag(sess: AsyncSession, gt: Dict[str, Any]) -> Tag:
return obj
async def _upsert_post(sess: AsyncSession, gp: Dict[str, Any], author_map: Dict[str, Author], tag_map: Dict[str, Tag]) -> Post:
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)
def _apply_ghost_fields(obj: Post, gp: Dict[str, Any], author_map: Dict[str, Author], tag_map: Dict[str, Tag]) -> None:
"""Apply Ghost API fields to a Post ORM object."""
obj.deleted_at = None # revive if soft-deleted
obj.uuid = gp.get("uuid") or obj.uuid
@@ -213,7 +208,29 @@ async def _upsert_post(sess: AsyncSession, gp: Dict[str, Any], author_map: Dict[
pt = gp.get("primary_tag")
obj.primary_tag_id = tag_map[pt["id"].strip()].id if (pt and pt["id"] in tag_map) else None # type: ignore[index]
await sess.flush()
async def _upsert_post(sess: AsyncSession, gp: Dict[str, Any], author_map: Dict[str, Author], tag_map: Dict[str, Tag]) -> Post:
from sqlalchemy.exc import IntegrityError
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()
_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:

2
shared

Submodule shared updated: 9a1a4996bc...24432cd52a