※AI関連作業・調査のメモ ディレクトリやファイル名はダミー
ChatGPT Plus 設定サーバ 作業・調査メモ

朝の定期投稿が安定しない。。。
定期投稿が朝に詰まったので、生成と配信を分けた話
OpenClawで複数の定期投稿を運用していると、朝の時間帯に生成処理が集中して、投稿漏れやタイムアウトが目立つようになりました。今回は、朝に投稿される学習問題、英語レッスン、脆弱性レポート、サーバーレポートなどを点検し、「生成」と「配信」を分ける形へ整理しました。
この記事では、実際のサーバ名、チャンネルID、ローカルパスなどはダミー化して、作業の考え方と構成だけをまとめます。
起きていた問題
朝の定期投稿では、次のような問題が重なっていました。
- 生成は成功扱いなのにDiscordへ配信されない
- Web検索を含むレポート生成がタイムアウトする
- OS cron環境で
nodeやopenclawが見つからない - 前日分のレポートを取得してしまう
特に問題だったのは、朝の投稿時刻に「本文生成」「Web検索」「ファイル更新」「Discord配信」をまとめて行っていたことです。生成が少し重くなるだけで、投稿時刻そのものが不安定になります。
資格模擬問題投稿の配信漏れ
資格模擬問題の朝投稿では、cron実行自体は ok なのに、配信状態が not-delivered になっていました。本文生成は終わっていたものの、最終的な投稿本文が配送側に渡らない状態です。
一時対応として、プロンプトを簡素化し、最終応答を投稿本文だけに固定しました。また、余計なツール利用やファイル読み書きを外し、強制実行で配信確認を行いました。
状態:
cron status: ok
delivery status: not-delivered
対応:
- 投稿本文だけを返す形へ簡素化
- 不要なツール利用を無効化
- 手動再実行で delivered を確認
サーバーレポートの時刻ずれ
サーバーレポートでは、OpenClaw側の取得時刻を朝の早い時間へ移動した一方で、対象サーバ側の生成timerが旧時刻のまま残っていました。そのため、OpenClaw側が取得する時点では当日分がまだ生成されておらず、前日分を拾う可能性がありました。
構成としては次のようなずれです。
対象サーバ側
旧: 09:10 レポート生成
OpenClaw側
新: 08:30 レポート取得
新: 08:35 Discord投稿
このままだと、08:30に取得するファイルは前日分です。対象サーバ側の生成timerを08:25へ移動し、OpenClaw側の取得・投稿と順序が合うようにしました。
対象サーバ側
08:25 レポート生成
OpenClaw側
08:30 レポート取得
08:35 Discord投稿
cron環境でnodeが見つからない問題
OS cronから投稿スクリプトを実行したとき、手元のシェルでは動くのにcronでは node が見つからない、という問題もありました。
原因はcronの環境変数が最小限で、通常のログインシェルで設定されるPATHが入っていないことです。投稿スクリプト側でPATHを明示するようにしました。
export PATH="/path/to/node/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
OPENCLAW_CLI="/path/to/openclaw"
これにより、cron相当の最小環境でも node と openclaw が解決できることを確認しました。
英語レッスンの重複
英語レッスンでは、前日と同じ英文が投稿されました。状態ファイルには前日の英文が記録されていたため、状態ファイルそのものが無いわけではありませんでした。
問題は、プロンプト上で状態ファイルの読み取りが「可能なら」という扱いだったことです。実行時に履歴を読まず、結果として同じ英文を再利用していました。
対応として、履歴ファイルの読み取りと更新を必須化し、読めない場合はcronの直近実行履歴から禁止リストを作るようにしました。
対策:
- 状態ファイルの読み取りを必須化
- 直近12件の英文を再利用禁止
- 直近6件の作品をできるだけ回避
- 状態ファイルが読めない場合は実行履歴を参照
脆弱性レポートのタイムアウト
脆弱性レポートは、Web検索と一次情報確認が重く、300秒の制限で何度もタイムアウトしていました。以前の成功例でも200秒前後かかっていたため、朝の定刻実行には余裕がありません。
短期対応として、検索回数、ページ取得数、掲載件数を絞り、timeoutを600秒へ延ばしました。そのうえで強制実行し、配信まで確認しました。
変更前:
最大5件
広めにWeb検索
timeout 300秒
変更後:
最大3件
Web検索 最大4回
ページ取得 最大6ページ
timeout 600秒
旧名の失敗通知が出た理由
スケジュール移動後に、旧名のジョブ失敗通知が各チャンネルへ出ることがありました。これは、旧時刻のスケジュールが実際に動いたというより、移動・リネーム前に走りかけていた実行がgateway restartで中断され、その失敗通知が旧名で配送されたものです。
確認すると、失敗実行の開始は旧スケジュール時刻ではなく、gateway restart前後の中途半端な時刻でした。その後、スケジュールは新時刻へ再計算され、さらにジョブ名を新時刻に合わせてリネームしました。
見え方:
Cron job "old-name-10jst" failed
実態:
- 移行前後に走りかけていた実行が中断
- 通知時点ではまだ旧名
- 次回予定は新時刻へ再計算済み
最終方針: 生成と配信を分ける
根本対策として、サーバーレポート以外の多くの投稿は、朝に生成しない方針へ切り替えました。夜間に本文を作ってファイルへ保存し、朝や昼はそのファイルを読むだけにします。
新しい構成は次の通りです。
夜間 01:00〜03:45
OpenClaw draft generation jobs
- 投稿本文を生成
- /path/to/workspace/reports/scheduled/<slug>.md に保存
- /path/to/workspace/reports/scheduled/<slug>.json にメタ情報を保存
朝/昼
OS cron
- 当日分の下書きか確認
- status=ready か確認
- Discord channel:<CHANNEL_ID> へ投稿
夜間生成へ移したもの
夜間生成へ移したのは、内容の鮮度が分単位ではなく、事前生成しても問題が少ない投稿です。
- 英語レッスン
- 資格模擬問題
- AI関連 更新情報
- 脆弱性レポート
- 簡単レシピ
- OpenClawイベント情報
- 子供向けお出かけ情報 など
生成時刻は、01:00から03:45まで15分間隔で分散しました。
現行維持したもの
一方で、情報の鮮度が必要なものは現行維持にしました。
- サーバーレポート
サーバーレポートは朝の実状態が重要です。夜間に作ると鮮度が落ちます。これらは投稿時刻に近いタイミングで生成・取得する方が自然です。
下書き配信スクリプト
配信用には、下書きファイルを読むだけのスクリプトを用意しました。ここでは実パスをダミー化しています。
post-scheduled-draft.sh <slug> channel:<CHANNEL_ID>
このスクリプトは、次の条件を満たさない場合は投稿しません。
<slug>.mdが存在する<slug>.jsonが存在するtargetDateが当日であるstatusがreadyである
古い下書きや生成途中の下書きを誤って投稿しないためです。
下書きの臨時生成で見つかった注意点
下書きの臨時生成での検証中、ジョブが ok なのにファイルが作られませんでした。
これは「ファイルを書けない設定」ではなく、cron側の ok が「エージェント実行が正常終了した」ことだけを表し、「ファイルが実際に作られた」ことまでは検証していないためです。
また、元プロンプトに「最終応答は投稿本文だけ」とあり、後付けの「ファイルへ保存してから draft saved と返す」という指示と競合していました。
対策として、全ての下書き生成ジョブの先頭に、次の趣旨の指示を追加しました。
このジョブは下書き生成専用です。
Discordへ投稿してはいけません。
元タスクに「最終応答は投稿本文だけ」と書かれていても、
必ず投稿本文を.mdへ保存し、メタ情報を.jsonへ保存してください。
今回の落としどころ
今回の整理で、朝の投稿時刻に重い生成処理を抱え込まない構成になりました。
- 重い生成は夜間に分散する
- 朝や昼はファイル配信だけにする
- 下書きには当日メタ情報を持たせる
- 投稿前に当日分かどうかを検証する
- 直接投稿ジョブは無効化して二重投稿を防ぐ
OpenClaw cronは生成に使い、OS cronは配信に使う、という責務分離です。生成は多少遅れても投稿時刻に直接影響しにくく、配信は軽い処理だけなので安定します。
まとめ
今回の対応では、朝の定期投稿の失敗をきっかけに、スケジュール全体を見直しました。短期的には、PATH不足、timerの時刻ずれ、プロンプトの曖昧さ、タイムアウトなどを個別に直しました。
ただ、根本的には「朝に全部やる」構成が不安定さを生んでいました。そこで、夜間に余裕を持って生成し、朝は検証済みの下書きを配信する方式へ変えました。
定期投稿は、生成成功と配信成功を分けて考えると安定します。特にWeb検索や長文生成を含む投稿では、投稿時刻に生成を走らせるより、事前生成と軽量配信に分ける方が運用しやすいと感じました。

