2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

本番(prod)サーバーに自動処理を組んだのでまとめ

2
Last updated at Posted at 2026-11-13

スクリーンショット 2026-11-06 13.48.28.png

今回は本番環境(prdサーバー)に自動処理の実行環境を設定しました。

  • 指定した時刻に記事を公開するための「予約公開」の仕組み
  • 画面操作とは別に処理を進める「AI審査」に対して採用

⭐︎この記事でわかること⭐︎
1:自動処理を組むとは
2:仕組みとメリット、デメリット
3:自動処理を支える5つの仕組み
4:今回組んだ自動処理とその採用理由

今回使用したのは
cron Laravelスケジューラ キュー Supervisor ワーカー
この5つを活用しています。

1:自動処理を組むとは

ここでいう「自動処理を組む」とは、
人がその都度コマンドを実行しなくても、
必要なタイミングで処理が動く環境を整えること

今回行ったのは、予約公開やAI審査そのものの新規実装ではなく、
アプリに実装済みの処理を自動で動かすためのサーバー設定です。

例えばこんなのがある

「決まったタイミングで繰り返す仕事」や「画面で完了を待たせたくない仕事」が候補になります。

機能 向いている仕組み 理由
記事の予約公開 定期実行 公開時刻に到達した記事を繰り返し確認できる
古い一時ファイルの削除 定期実行 毎日など、一定間隔で実行できる
定期集計・レポート作成 定期実行+必要ならキュー 作成時刻の管理と重い処理の分離ができる
メール通知 非同期処理 通信待ちを画面操作から分離できる
画像変換・CSV出力 非同期処理 時間のかかる処理を後から実行できる
AI審査・外部API連携 非同期処理 外部サービスの応答待ちを分離できる

2:仕組みとメリットデメリット

「定期実行」と「非同期処理」を分けて考える

自動処理を理解するうえでは、次の2つを分けると整理しやすくなりました。

  • 定期実行:指定した時刻や間隔で処理を動かす。例:予約公開
  • 非同期処理:その場で処理完了を待たず、
    仕事を登録して別のプロセスで実行する。例:AI審査、ファイル生成

また、この2つは組み合わせたりもできるので用途に応じて導入しましょう。

メリット

  • 手動実行の手間や、実行し忘れを減らせる
  • 定期的に確認が必要な処理を、自動で呼び出せる
  • 時間のかかる仕事を画面操作から分離できる
  • ワーカーが終了した場合も、Supervisorで再起動できる

デメリット・注意点

  • 画面から見えないところで動くため、ログや失敗の監視が必要
  • 非同期処理は、依頼した直後に結果が出るとは限らない。画面にも「処理中」などの状態が必要になる
  • 再試行で同じ仕事が複数回実行される可能性がある。二重投稿などを防ぐ設計も必要
  • ワーカーを増やすとDBや外部APIへの負荷も増える
  • 常駐ワーカーは読み込んだコードを保持するため、デプロイ後の再起動を考える必要がある

何でもかんでも自動化したら良い、というわけではなさそうです。

3:自動処理を支える5つの仕組み

名前 たとえるなら 役割
cron 時計係 指定した時刻・間隔でコマンドを起動する
Laravelスケジューラ 予定表係 登録された予定から、今実行する定期処理を選ぶ
キュー 仕事の受付 実行待ちの仕事を保存する
ワーカー 作業員 キューから仕事を取り出して実行する
Supervisor 現場監督 ワーカーを起動・監視し、終了したら再起動する

cron:時間管理のプロ

スクリーンショット 2026-11-10 14.29.36.png
Unix系オペレーティングシステムのジョブ管理ツール
cronジョブ(コマンドまたはシェルスクリプト)を登録すると、
指定した日時または間隔でジョブを実行してくれます

cronは、主にシステムの管理・維持を自動化する目的で使用されるが、
ファイルを定期的にダウンロードするコマンドを
起動するなどの用途にも応用できるみたいで
めっちゃ優秀です。

Laravelスケジューラ:予定管理係

スクリーンショット 2026-11-10 14.30.11.png
Laravelのコードで「どの処理を、いつ実行するか」を管理する仕組みです。
「毎分」「毎日」「毎週」などの実行予定を登録できます。

cronから呼び出されると、登録された予定を確認し、
その時点で実行対象になっている処理を選んで実行します。
処理ごとの予定をLaravel側にまとめられるので、アプリのコードとして管理しやすいのが
便利なところです。

今回の予約公開では、スケジューラが公開用の
コマンドを呼び出し、

その処理が公開時刻を過ぎた記事を確認します。
スケジューラ自身が記事の内容まで判断しているわけではありません。

キュー:仕事の受付係

スクリーンショット 2026-11-10 14.32.17.png

後から実行する仕事を保存しておく、待ち行列の仕組みです。
この仕事の単位を、Laravelでは「ジョブ」と呼びます。

例えば、画面からAI審査を依頼したときに、その依頼をジョブとして登録しておきます。
キューは依頼を預かる場所なので、キューだけ用意しても、仕事は実行されません。

今回はDBにジョブを保存する方式を使いました。
通常処理用とAI審査用でキューを分け、それぞれの担当ワーカーが仕事を取り出す構成です。

ワーカー:従順な作業員

スクリーンショット 2026-11-10 14.32.57.png

キューに登録された仕事を取り出し、実際に処理するプロセスです。
キューが受付なら、ワーカーは依頼票を受け取って動く作業員にあたります。

Laravelでは、queue:work コマンドなどでワーカーを起動します。
起動したワーカーは担当するキューを確認し、仕事があれば処理を進めます。

今回は、通常処理用とAI審査用にワーカーを1つずつ用意しました。
担当を分けることで、AIの応答を待っている間も、
通常処理を進められるようにしています。

スーパーバイザー:現場監督

スクリーンショット 2026-11-10 14.33.13.png

Supervisorは、プロセスを起動・監視するためのツールです。
今回はワーカーを常駐させ、終了した場合に自動で起動し直す役割を任せました。

手動でワーカーを起動するだけでは、終了したときに気づかず、
仕事がキューにたまってしまう可能性があります。
そこで、ワーカーを動かし続けるための管理をSupervisorに任せる構成にしました。

ただし、Supervisorが監視するのはプロセスの状態です。
ワーカーが動いていても個々のジョブは失敗することがあるため、
処理結果やエラーログは別に確認が必要です。

4:今回採用した自動処理、採用理由

スクリーンショット 2026-11-13 15.45.34.png

スクリーンショット 2026-11-13 15.47.12.png

予約公開などの定期処理:cron+Laravelスケジューラ

今回は、cronから毎分 schedule:run を起動する構成にしました。

役割を会話にすると、こんなイメージです。

cron:「1分経ったよ! 今、実行する予定はある?」
Laravelスケジューラ:「予定を確認するね。予約公開の処理を動かす時間だ!」

予約公開処理:「公開時刻を過ぎた記事があるか確認して、対象の記事を公開するよ!」

cronには定期的に呼び出す役割を任せ、どの処理を
いつ動かすかはLaravel側で管理します。
処理ごとにcronを増やすよりも、
アプリのコードで予定を追いやすくするためです。

ただし、確認は毎分です。
「予約時刻になった瞬間、秒単位で必ず公開される」
という構成ではないのでアプリとの整合性確認は
しっかりした上で実装しましょう。
スクリーンショット 2026-11-13 15.48.39.png

通常処理とAI審査:キュー+ワーカー

DBキューを使い、通常処理用と
AI審査用にワーカーを1つずつ用意しました。

アプリ:「AI審査をお願いしたいので、仕事を登録します!」
キュー:「依頼を預かったよ。担当のワーカーが取り出すまで保存しておくね!」
AI審査ワーカー:「審査の仕事を取り出したよ。AIに問い合わせて、結果を反映します!」
通常ワーカー:「その間も、こちらは通常の仕事を進めるよ!」

担当を分けることで、AIの応答待ちで通常の仕事まで
詰まるのを避けています。
キューは保存先、ワーカーは実行担当という違いが
あります。

また、すべての処理がキューを通るわけではありません。
今回の予約公開では、次のようにつながっています。

予約公開処理:「記事を公開したよ。必要なSNS投稿はキューに登録しよう!」
通常ワーカー:「登録されたSNS投稿の仕事は、こちらで取り出して処理するね!」

スクリーンショット 2026-11-13 15.49.19.png

ワーカーの常駐管理:Supervisor

ワーカーを毎回手動で起動する運用にせず、
Supervisorに起動・監視・再起動を任せました。

Supervisor:「ワーカーを起動します。動いているかも見守るよ!」
ワーカー:「起動しました! キューの仕事を確認します!」
Supervisor:「ワーカーが終了したことを検知したので、起動し直します!」
これで、ワーカーが終了した場合にも自動で再起動できます。
でもSupervisorが見ているのは「プロセスの状態」
なので注意です。
ワーカー:「プロセスは動いているけれど、この仕事はエラーになりました……」
運用担当:「それは処理結果やエラーログを確認する必要があるわね!」

ワーカーが動いていることと、すべての仕事が成功して
いることは別なので、ジョブの失敗確認は引き続き必要になります。

参考:色々なプロセスの状態

表示例 意味
STARTING 起動している途中
RUNNING 起動して稼働中
STOPPED 停止している
EXITED 実行が終了した
FATAL 起動を繰り返し試しても成功しなかった

スクリーンショット 2026-11-13 15.50.47.png

設定の流れ(本番環境向けの架空例)

実際に設定・確認したのはSTGです。以下はその構成をもとに、本番環境向けの架空名で説明した例です。本番環境への適用実績を示すものではありません。
cronとSupervisorは導入・起動済みで、アプリのDBキューを利用できることを前提とします。
Supervisorの設定は、読み込み対象の /etc/supervisor/conf.d/example-worker.conf へ記述する想定です。
※このコマンド群は環境によって異なるため
基本的には全てexampleとしています。各々の環境に合わせ記述する必要があります

まずは本番環境に潜り込む

1:まずは本番環境に潜り込む
# 本番環境へSSH接続する(接続先は架空の例)
ssh prod.example.com
コレ以降のコマンドは本番環境内で実行する。

cron(時間管理のプロ)を設定

cronの設定ファイルを管理者権限で編集する

コード・設定例を表示
sudoedit /etc/cron.d/example-scheduler

cronがコマンド実行に使うシェル
コマンドを探すディレクトリの設定。
PHPの子プロセスなどにも使われる

コード・設定例を表示
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

* * * * * appuser cd /srv/example-app/current && /usr/bin/php artisan schedule:run >> /dev/null 2>&1

ここむずいので下に書きます。

部分 意味
* * * * * 毎分実行する
appuser このユーザーの権限で実行する
cd /srv/example-app/current アプリのフォルダへ移動する
&& 前のコマンドが成功したら、次を実行する
/usr/bin/php 使用するPHPの実行ファイル
artisan schedule:run Laravelに実行予定を確認させる
>> /dev/null 2>&1 通常出力とエラー出力を破棄する

なぜ破棄する必要があるんです?
毎分の出力でcronの通知メールなどが大量に発生するのを避けるため、
捨てる設定にしている

ログを残すときはこんな感じに
『>> /書き込み可能なパス/scheduler.log 2>&1』

実際にはコマンドの末尾に付けます。実行ユーザーが
書き込める保存先を使い、ログの容量管理も必要です。

スーパーバイザーの設定

「この作業員を1人起動して、終了したら補充し、活動記録も残してね」
という設定をします。

コード・設定例を表示

; ── ① 何を動かすか ──

; Supervisor内で使う、このワーカーの名前
[program:example-worker]

; アプリのフォルダ
directory=/srv/example-app/current

; このコマンドでワーカーを起動する
command=/usr/bin/php /srv/example-app/current/artisan queue:work --sleep=3 --tries=3 --timeout=600 --max-time=3600

; 実行するユーザーと、起動する作業員の人数
user=appuser
numprocs=1


; ── ② どう管理するか ──

; Supervisorの起動時に、ワーカーも起動する
autostart=true

; 稼働後にワーカーが終了したら、起動し直す
autorestart=true

; 停止要求後、最大660秒は終了を待つ
stopwaitsecs=660

; 子プロセスもまとめて停止の対象にする
stopasgroup=true
killasgroup=true


; ── ③ どこに記録するか ──

; エラーも同じログへまとめる
redirect_stderr=true

; ログの保存先
stdout_logfile=/srv/example-app/storage/logs/worker.log

; 50MBごとにログを切り替え、過去5世代を保存する
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=5
オプション 意味
--sleep=3 仕事がなければ3秒待つ
--tries=3 最大3回試す。Job側に指定があればそちらが優先
--timeout=600 1件の処理の制限時間。Job側の指定も確認
--max-time=3600 約1時間で、処理中の仕事が終わってからワーカーを終了する

AI審査には専属の作業員を用意する

通常の仕事とAI審査を同じ作業員に任せると、AIの返事を待っている間、
通常の仕事が後ろで待つことがあります。
そこで、AI審査のキューだけを担当する作業員をもう1人用意しました。

通常ワーカー:「こちらは通常の仕事を進めます!」
AI審査ワーカー:「AIの返事待ちはこちらで引き受けます!」

設定ファイルは同じで大丈夫です。通常ワーカーの設定の下に、別の名前で追加します。

AI審査用ワーカーの設定例
; ── ① AI審査の仕事だけを担当する ──
[program:example-review-worker]
directory=/srv/example-app/current

; --queue=example-review:この名前のキューだけを確認する
; --timeout=180:処理時間の上限を180秒にする
command=/usr/bin/php /srv/example-app/current/artisan queue:work --queue=example-review --sleep=3 --tries=3 --timeout=180 --max-time=3600

; 実行ユーザーと人数は通常ワーカーと同じ
user=appuser
numprocs=1

; ── ② 起動・停止を管理する ──
autostart=true
autorestart=true

; 停止要求後は、最大240秒待ってから強制終了する
stopwaitsecs=240
stopasgroup=true
killasgroup=true

; ── ③ AI審査用のログへ記録する ──
redirect_stderr=true
stdout_logfile=/srv/example-app/storage/logs/example-review-worker.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=5

通常ワーカーとの違いは、この4つです。

変える場所 どう変える?
[program:...] 別のワーカーとして管理できるよう、名前を変える
command AI審査用キューを指定し、制限時間を180秒にする
stopwaitsecs 停止要求後に待つ時間を240秒にする
stdout_logfile AI審査専用のログへ分ける

「受付を分ける」だけでなく、その受付を担当する作業員も別に起動するのがポイントです。
ジョブを登録する側のキュー名も、example-review に合わせる必要があります。

同じ仕事を早く配り直さないようにする

ここで、もう1つ時間の設定が登場します。

キューには、作業員が途中で止まってしまっても仕事が
放置されないように、一定時間が過ぎたら、処理中の仕事を
再び取り出せるようにする仕組みがあります。

ただ、その時間が短すぎると……。

受付:「時間が過ぎたので、この依頼はもう一度取り出せます!」
作業員A:「待って! まだ処理してます!」
作業員B:「同じ依頼を受け取ってしまいました……」

これでは、同じ仕事を重複して実行する可能性があります。
そこで、処理を打ち切るまでの時間より、
再取得できるようになるまでの時間を長くします。

設定 今回の値
通常処理の制限時間 600秒
AI審査の制限時間 180秒
処理中の仕事を再取得可能にするまでの時間 660秒
DBキューの環境設定例
# 処理中のジョブを、再び取り出せるようにするまでの秒数
# 実行周期や、失敗後の待ち時間(backoff)とは別の設定
DB_QUEUE_RETRY_AFTER=660

既存の環境設定の該当項目を変更します。ファイル全体を
この1行で上書きするわけではありません。

「毎回660秒待ってから仕事を始める」という意味ではないので、
ここは混乱しやすいところでした。
この設定は重複実行のリスクを抑えるもので、完全に防ぐ保証ではありません。
処理側でも、同じ仕事を再実行したときの対策が必要です。

書いた設定を読み込ませる

設定ファイルを書いて終わり、ではありません。
LaravelとSupervisor、それぞれに変更を反映します。

設定を反映するコマンド例
# ① アプリのフォルダへ移動
cd /srv/example-app/current

# ② Laravelの設定キャッシュを作り直す
sudo -u deployuser /usr/bin/php artisan config:cache

# ③ Supervisorに「設定が変わっていないか確認して」と伝える
sudo supervisorctl reread

# ④ 対象ワーカーに設定を適用する
# 追加したワーカーは起動し、設定が変わったワーカーは再起動する
sudo supervisorctl update example-worker example-review-worker

reread は変更の確認、update は変更の適用です。

なお、Laravelの環境設定だけを変えた場合、Supervisorの設定に
差分がなければ、update だけでは既存ワーカーは再起動しません。

すでに動いているワーカーへ新しい設定やコードを読み込ませる場合は、
次のように再起動を要求します。

処理を終えてからワーカーを再起動する
# 処理中の仕事が終わったら終了するよう、ワーカーへ要求する
sudo -u appuser /usr/bin/php \
  /srv/example-app/current/artisan queue:restart

ワーカー:「今の仕事を終えたので、一度終了します!」
Supervisor:「終了を確認したので、新しく起動します!」

こうすることで、新しいコードや設定を読み込んだワーカーが起動します。
この要求はLaravelのキャッシュを使うため、コマンドとワーカーが
同じキャッシュを参照していることも必要です。

最後に、本当に動いているか確認する

まずは、作業員が出勤しているかを確認します。

ワーカーの状態を確認する
sudo supervisorctl status

表示イメージはこんな感じです。名前は公開用に置き換えています。

ワーカーの表示例
example-worker         RUNNING
example-review-worker  RUNNING

2つとも RUNNING なら、ワーカーは起動しています。
次に、時計係が毎分スケジューラを呼び出しているかを確認します。

cronの実行ログを確認する
# スケジューラに関するログの末尾6行を表示する
sudo grep 'artisan schedule:run' /var/log/cron | tail -6
cronログの表示例(省略)
03:00:01  CMD     (... artisan schedule:run ...)
03:00:03  CMDEND  (... artisan schedule:run ...)
03:01:01  CMD     (... artisan schedule:run ...)
03:01:03  CMDEND  (... artisan schedule:run ...)
表示 分かること
RUNNING ワーカーが起動している
CMD cronがコマンドを開始した
CMDEND cronがコマンドを終了した

監督:「作業員2人、出勤しています!」
時計係:「毎分、予定の確認を呼び出しています!」
運用担当:「では、記事が公開されたか、AI審査の結果が反映されたかも確認しましょう!」

「プロセスが動いた」と「機能が期待どおり動いた」は別
ということです。

実際の作業では、2026年11月6日に本番環境で、
ワーカー2つの稼働・cronの毎分実行・Webの正常応答まで
確認しました。

テスト記事の予約公開、AI審査結果の反映、実際のサーバー再起動後の
復帰は、その時点では未確認です。
上のログは当時の結果をもとにした省略例で、現在の稼働状況を
示すものではありません。

今回、設定しただけで満足せず、
「どこまで確認できたか」も分けて残す必要があると学びました。

まとめ

今回は、本番環境(prod)で、実装済みの予約公開や
AI審査を自動で動かすための設定を行いました。

役割を整理すると、次の5つになります。

  • cron:指定した間隔でコマンドを起動する
  • Laravelスケジューラ:今実行する定期処理を選ぶ
  • キュー:実行待ちの仕事を保存する
  • ワーカー:キューから仕事を取り出して実行する
  • Supervisor:ワーカーの起動・監視・再起動を管理する

通常処理とAI審査のワーカーを分け、AIの応答待ちで通常処理が
詰まらない構成にしました。また、処理時間と再試行間隔を調整し、
同じ仕事が重複して実行されるリスクを抑えています。

今回学んだのは、自動処理は「勝手に動くようにする」だけでなく、
「失敗に気づき、確認できるようにする」ことも大切
ということです。

ワーカーの稼働とcronの実行は確認できましたが、予約公開やAI審査の結果
まで正しいかは別の確認になります。
今後は、実際の機能を通した動作確認も進めていきたいと思います。

参考資料

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?