자동화 slecs

봇 자동 생성 콘텐츠를 CMS에 이중 기록하는 구조 도입

목차

어드민 DB dual-write 구조를 붙이면서 CMS 포스트 UPSERT 흐름을 정리한 작업이다.

왜 dual-write가 필요했나

봇이 콘텐츠를 자동 생성해서 내보내는 구조에서, 생성 결과물이 어디에 기록되는지가 운영 관점에서 꽤 중요한 문제다. 기존에는 봇이 생성 → 배포 채널로 직접 밀어넣는 단방향이었는데, 이렇게만 두면 나중에 "이거 언제 생성됐어?", "이 포스트 내용 다시 볼 수 있어?" 같은 요청이 왔을 때 추적이 안 된다.

운영자 입장에서 CMS는 진짜 레코드의 원천이 되어야 하고, 봇이 뭔가를 자동 생성했다면 그 결과물도 CMS에 반드시 찍혀 있어야 한다는 게 이번 작업의 전제였다. dual-write라는 표현을 쓴 이유는, 봇이 기존 배포 흐름을 유지하면서 동시에 admin_db에도 레코드를 남기는 구조이기 때문이다.

작업 내용

변경된 파일은 세 개다.

파일 역할 이번 변경 의미
bot/admin_db.py 어드민 DB 커넥션 / 쿼리 레이어 UPSERT 쿼리 및 연결 로직 신규 추가
bot/generate.py 콘텐츠 생성 메인 로직 생성 완료 후 admin_db write 호출 삽입
bot/requirements.txt 의존성 DB 드라이버 등 신규 패키지 추가

admin_db.py를 별도 모듈로 뺀 건 의도적인 선택이다. generate.py에 DB 로직을 인라인으로 때려박으면 나중에 테스트하기도 불편하고, 다른 봇 모듈에서 같은 DB 레이어를 재사용할 때 복붙이 생긴다. 분리해두면 generate.py는 생성 책임만 가져가고, DB 기록은 admin_db.py가 담당하는 구조가 된다.

UPSERT를 선택한 이유도 짚고 넘어갈 필요가 있다. INSERT만 하면 봇이 재실행됐을 때(재시도, 스케줄 중복 등) 동일 포스트 키로 중복 레코드가 쌓인다. DELETE + INSERT는 히스토리 날아가는 문제가 있다. 결국 UPSERT가 가장 무난한 선택이고, cms_post 테이블 기준으로 포스트 식별 키가 이미 있으면 갱신, 없으면 삽입하는 흐름으로 정리했다.

# admin_db.py — UPSERT 패턴 (개념 예시)
def upsert_cms_post(conn, post_data: dict):
    sql = """
        INSERT INTO cms_post (post_key, title, body, generated_at)
        VALUES (%(post_key)s, %(title)s, %(body)s, %(generated_at)s)
        ON CONFLICT (post_key)
        DO UPDATE SET
            title = EXCLUDED.title,
            body = EXCLUDED.body,
            generated_at = EXCLUDED.generated_at
    """
    with conn.cursor() as cur:
        cur.execute(sql, post_data)
    conn.commit()

generate.py에서는 생성 로직이 끝난 직후 이 함수를 호출하는 식으로 연결했다. 생성 실패 시에는 write도 하면 안 되기 때문에, 생성 성공 확인 이후 write 순서를 명확히 지키는 게 포인트였다.

팀 관점에서 이 변경이 갖는 의미

dual-write 구조를 붙이는 건 단순한 기능 추가가 아니다. 이제 봇이 DB 의존성을 갖게 되었기 때문에, 배포 환경에서 DB 연결 설정 / 시크릿 관리 / 연결 실패 시 fallback 여부 등을 팀이 함께 인지해야 한다.

특히 이런 지점들을 리뷰에서 짚었다:

  • DB write 실패 시 생성 결과 배포 자체를 막을 건지, 아니면 write만 실패 처리하고 배포는 계속할 건지 — 현재는 write 실패가 전체를 막는 구조로 우선 갔다
  • requirements.txt에 추가된 패키지가 CI/CD 이미지 빌드에 영향을 주는지 — 확인 필요
  • 로컬 개발 환경에서 admin_db 연결 없이 봇 단독 실행이 가능한지 — 환경변수 미설정 시 graceful하게 skip할 수 있도록 후속 처리 예정

automation 카테고리 작업에서 DB 연동이 들어가는 순간, "봇이 가끔 실패해도 괜찮은 존재"에서 "DB 정합성을 다루는 존재"로 성격이 바뀐다. 이 무게감을 팀 전체가 공유하는 게 코드 변경 자체보다 더 중요했다.


다음은 write 실패 시 재시도 로직과 dead-letter 처리 방향을 정리할 것 같다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.