832ea72784
backfill_publish_* 가 단일 호출(after_id=0, limit=PAGE)이라 PAGE 초과분이 누락(경고만)됐다. docstring 은 이미 페이지 반복을 명시했으나 스크립트가 미구현. 함수 반환을 (count, last_id)로 바꾸고 3 스크립트를 last_id 기반 while 루프로 전량 처리. PAGE=5000 bounded tx. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
"""S-2 초기 백필 — 검수완료(needs_review=False)·미삭제 study_memo_cards 를 발행 outbox 에 적재.
|
|
|
|
publish_outbox 에만 적재(멱등: 워커 (payload_hash, deleted) 디둡). study_publish_enabled=True
|
|
일 때 발행 워커가 drain → published(kind=study_card) rev 부여 → viewer pull-sync.
|
|
|
|
실행 (GPU 서버):
|
|
docker exec hyungi_document_server-fastapi-1 python /app/scripts/backfill_publish_cards.py
|
|
docker exec hyungi_document_server-fastapi-1 python /app/scripts/backfill_publish_cards.py --dry-run
|
|
"""
|
|
|
|
import argparse
|
|
import asyncio
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
|
|
# standalone-model-registry-fix: app(라우터 경유 전 모델 import)과 달리 script 는 부분 모델만
|
|
# import → SQLAlchemy mapper string 관계(StudyTopic.sessions->StudySession 등) 해소 실패.
|
|
# 전 모델 모듈 import 로 레지스트리 완성(전부 컨테이너서 import 가능 = app 이 기동 시 로드).
|
|
import importlib as _il, pkgutil as _pu
|
|
import models as _mp
|
|
for _m in _pu.iter_modules(_mp.__path__):
|
|
_il.import_module("models." + _m.name)
|
|
|
|
|
|
from sqlalchemy import func, select
|
|
|
|
from core.config import settings
|
|
from core.database import async_session
|
|
from models.study_memo_card import StudyMemoCard
|
|
from services.study.publish_enqueue import backfill_publish_cards
|
|
|
|
# 페이지 배치 크기 — after_id 루프로 전량 처리(bounded tx). 워커는 BATCH_SIZE 로 drain.
|
|
PAGE = 5000
|
|
|
|
|
|
async def run(dry_run: bool) -> None:
|
|
async with async_session() as session:
|
|
active = (
|
|
await session.execute(
|
|
select(func.count())
|
|
.select_from(StudyMemoCard)
|
|
.where(
|
|
StudyMemoCard.deleted_at.is_(None),
|
|
StudyMemoCard.needs_review.is_(False),
|
|
)
|
|
)
|
|
).scalar() or 0
|
|
|
|
print(f"[info] study_publish_enabled={settings.study_publish_enabled} "
|
|
f"(False 면 적재는 되나 워커가 drain 안 함)")
|
|
print(f"[info] 검수완료·미삭제 카드 {active}건")
|
|
if dry_run:
|
|
print("[dry-run] 적재 안 함. 실제 실행은 --dry-run 제거.")
|
|
return
|
|
|
|
total = 0
|
|
after = 0
|
|
while True:
|
|
async with async_session() as session:
|
|
n, after = await backfill_publish_cards(session, after_id=after, limit=PAGE)
|
|
await session.commit()
|
|
total += n
|
|
if n < PAGE:
|
|
break
|
|
|
|
print(f"\n[ok] outbox 적재 {total}건 — 발행 워커가 drain(flag on 시) 하며 rev 부여.")
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="S-2 pub_card 초기 백필")
|
|
parser.add_argument("--dry-run", action="store_true", default=False)
|
|
args = parser.parse_args()
|
|
asyncio.run(run(args.dry_run))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|