AIでブログ記事の自動生成・投稿を組むと、生成自体は成功しても「画像だけ先にアップされた」「投稿が重複した」「公開ステータスだけ反映されない」といった部分的な失敗が起こりがちです。こうした状態で単純に再実行すると重複投稿やデータ不整合を招きます。本稿では制作現場で使える実例を中心に、失敗した工程から安全に再開(リカバリ)するための設計パターンと実装例を示します。
失敗パターンを分類する(まずは原因を明確にする)
再開設計は、どこで何が失敗したかを特定できることが前提です。以下の主要パターンを意識してください。
- 完全失敗:生成→アップロード→投稿まですべて完了していない
- 部分成功:画像アップは成功、記事投稿だけ失敗など工程間で差がある
- 重複実行:ネットワークタイムアウト後に再送した結果、同一記事が2件生成される
- 外部依存エラー:CMSや画像CDN側の一時的エラー
設計方針(安全に再開するための基本ルール)
- アイドンポテンシー(idempotency)を採る:同じ仕事を複数回実行しても副作用が1回だけになる設計にする
- 工程を小さなトランザクションに分割し、各工程の完了状態を永続化する
- 「暫定状態(draft)」を使う:公開は最後のステップに限定し、中間は下書きで保存する
- 明確なチェックポイント(チェック済みフラグ/タイムスタンプ)を持つ
- ログと操作履歴を残し、手動での差し戻しや確認ができるようにする
実装パターン:ワークフローの例(生成→画像→下書き→公開)
現場で使いやすい順序と安全措置の例です。各工程で結果をDBに記録し、再開時にはDBの状態を見て次の工程を決めます。
- AIで本文とメタ情報を生成(生成IDを発行)
- 画像生成/取得し、画像IDを取得(失敗したらリトライキューへ)
- CMSに対して「下書き(draft)」で投稿を作成、戻り値のpost_idを保存
- 最終チェック(プレビューまたは自動チェック)を経て「公開(publish)」に変更
利点
- 公開を最後に限定することで重複公開や未完成公開を防げる
- 中間状態があるため手動確認や差分修正が容易
コード例:PythonでIDEMPOTENTな投稿処理(概念実装)
以下は概念的な実装例です。SQLiteでジョブを管理し、WordPress REST APIに下書きで投稿、成功したら公開する流れを示します。
# requirements: requests
import sqlite3
import requests
import time
import uuid
DB = 'jobs.db'
WP_API = 'https://example.com/wp-json/wp/v2'
WP_AUTH = ('user','pass') # 実運用ではOAuthやJWTを推奨
# 初回セットアップ(テーブル)
conn = sqlite3.connect(DB)
conn.execute('''
CREATE TABLE IF NOT EXISTS jobs (
job_id TEXT PRIMARY KEY,
content_hash TEXT,
status TEXT,
attempts INTEGER DEFAULT 0,
post_id INTEGER,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
# ジョブ登録
def create_job(content_hash):
job_id = str(uuid.uuid4())
conn = sqlite3.connect(DB)
conn.execute('INSERT INTO jobs(job_id, content_hash, status) VALUES(?,?,?)',
(job_id, content_hash, 'created'))
conn.commit()
conn.close()
return job_id
# 投稿処理(retry/ idempotency)
def process_job(job_id, title, content):
conn = sqlite3.connect(DB)
cur = conn.cursor()
cur.execute('SELECT status, attempts, post_id FROM jobs WHERE job_id=?', (job_id,))
row = cur.fetchone()
if not row:
raise Exception('job not found')
status, attempts, post_id = row
# 既に公開済みなら何もしない(idempotent)
if status == 'published' and post_id:
print('already published:', post_id)
conn.close()
return
# 画像アップ等は別工程として扱う(ここでは省略)
# 下書きが未作成なら作成する
if status in ('created','draft_failed'):
payload = {'title': title, 'content': content, 'status': 'draft'}
r = requests.post(f'{WP_API}/posts', json=payload, auth=WP_AUTH, timeout=10)
if r.status_code == 201:
post = r.json()
cur.execute('UPDATE jobs SET status=?, post_id=?, attempts=attempts+1, updated_at=CURRENT_TIMESTAMP WHERE job_id=?',
('draft_created', post['id'], job_id))
conn.commit()
post_id = post['id']
else:
cur.execute('UPDATE jobs SET status=?, attempts=attempts+1 WHERE job_id=?',
('draft_failed', job_id))
conn.commit()
conn.close()
raise Exception('failed to create draft: ' + r.text)
# 最終公開
if status in ('draft_created','publish_failed') or (status == 'created' and post_id):
# ここで自動チェック(プレビュー検証など)を入れても良い
r2 = requests.post(f'{WP_API}/posts/{post_id}', json={'status': 'publish'}, auth=WP_AUTH, timeout=10)
if r2.status_code == 200:
cur.execute('UPDATE jobs SET status=?, attempts=attempts+1, updated_at=CURRENT_TIMESTAMP WHERE job_id=?',
('published', job_id))
conn.commit()
else:
cur.execute('UPDATE jobs SET status=?, attempts=attempts+1 WHERE job_id=?',
('publish_failed', job_id))
conn.commit()
conn.close()
raise Exception('failed to publish: ' + r2.text)
conn.close()
# 再開側のロジックはDBのstatusを見て決められる
上記のポイント:
- ジョブに固有ID(job_id)を付与し、状態(status)をDBに保持する
- 「draft_created」「published」等の状態で分岐することで、処理を安全に再開できる
- 複数回実行されても既にpublishedなら何もしない(idempotency)
部分成功(画像だけ先にアップされた)を安全に扱う方法
よくある例は画像がCDNにアップされ、投稿作成が失敗した場合です。次の点を設計に入れてください。
- 画像の外部保存時に内部で参照可能なimage_idを得てジョブに紐づける
- 投稿作成時はimage_idを参照してメディアを添付する(IDベースで管理すると重複アップロードを避けられる)
- 万一画像が作成済みで投稿が未作成なら、再実行側はimageの再アップを行わず既存のimage_idを使う
リトライ戦略とバックオフ(現場での実践例)
- 短時間の一時エラーには指数バックオフで再試行(例:1s, 2s, 4s, 8s)
- 一定回数を超えたら自動停止して人による確認を促す(例:5回)
- 恒久的エラー(認証失敗など)は即時停止してアラートを投げる
自動化は便利ですが、人の介入ポイント(手動承認・差し戻しUI)を必ず残してください。
運用チェックリスト(導入後に最低限見るべき項目)
- ジョブテーブルに未完了(draft_failed / publish_failed)レコードが溜まっていないか
- 重複した投稿スラッグや同一content_hashの複数投稿がないか
- 外部API(CMS/CDN)のレスポンスコードとエラーメッセージを監視しているか
- 公開前に自動QA(言及チェック、著作権キーワードなど)を挟んでいるか
テスト方法(安全性を確認する手順)
- ローカル/ステージング環境で故意に部分失敗を作り、再開ロジックが期待通り動くか確認する
- ネットワーク障害を模してリトライ・バックオフを検証する(toxiproxy等)
- 同一ジョブを並列に2回起動してidempotencyが守られるか検証する
よくあるミスと回避策
- ミス: 投稿作成→公開を一度に行う。回避: 下書き保存を経由する
- ミス: 画像をURLベースで無制限に再アップする。回避: 画像にユニークIDを持たせる
- ミス: DBに状態を持たずログだけで管理する。回避: 明示的なジョブテーブルを用いる
まとめ
AIを使った自動投稿で失敗から安全に再開するための鍵は「状態の永続化」と「同一ジョブの冪等性」です。工程を小さく分けてチェックポイントを設け、下書き→公開と公開を最後に限定するワークフローにすることで、多くの失敗ケースを安全に処理できます。実装面ではジョブテーブル、idempotencyキー、画像ID管理、指数バックオフ、手動差し戻しUIの組み合わせが実用的です。まずはステージングで部分失敗を意図的に作るテストを行い、本番運用に入る前に再開フローを確実に確認してください。



コメント