【第7回】寝ている間にAIが働く!AlmaLinux 9のCronとPHPで作るバッチ処理完全自動化

「待たせないWeb」と「裏で働くAI」を分離するアーキテクチャ

こんにちは!「LINUX工房」管理人の「リナックス先生」です。
前回の第6回では、悪意あるアクセスからAPI破産を防ぐための強固な「多段防御(レート制限とFail2ban)」を構築しました。
これでWebアプリケーションとしての安全性は担保されましたが、本格的なAIサービスを運用していくと、すぐに「処理時間(タイムアウト)」という新たな壁にぶつかります。

コウ君

先生!ユーザーが投稿した長い記事を、AIに自動で要約させる機能を作ってみたんです。
でも、記事が10件くらい溜まると、ブラウザの画面がずっと「くるくる」回ったままで、最後に「504 Gateway Timeout」ってエラー画面になっちゃいます……。AIのAPIって時間がかかるから、Web画面で待たせるのは限界がありますよね?

リナックス先生

その通りよ、コウ君。
ApacheやPHPは本来「数ミリ秒〜数秒で結果を返す」ように設計されているの。数十秒から数分かかるAIの処理を、ユーザーがブラウザを開いたまま待たせるのはアーキテクチャとして完全に間違っているわ。
こういう時間のかかる処理は、ユーザーから切り離して、サーバーの裏側で「バッチ処理」として自動実行させるのがプロの定石よ。今日はLinux最強の自動化ツール「Cron」を使って、AIを24時間働かせる仕組みを作るわよ!

本記事では、AlmaLinux 9標準のジョブスケジューラ「Cron」とPHP(CLI版)を組み合わせ、AIによる一括処理や、サーバーのストレージ保守(不要ファイルの自動削除)を完全自動化する手法を解説します。


1. バッチ処理(非同期処理)が必要なAIのユースケース

Webブラウザからのリクエストに対して即座にAIの回答を返す「同期処理」に対し、裏側で時間をかけて処理を行うことを「非同期処理(バッチ処理)」と呼びます。
AIサーバーサイド開発において、バッチ処理が必須となるのは以下のようなケースです。

  • 大量データの要約・翻訳: 1日に投稿された数百件のユーザーレビューを、夜間にまとめてAIに感情分析(ポジティブ/ネガティブ)させる。
  • RAG用ナレッジの自動更新: 社内Wikiや新しいPDFマニュアルが追加された際、数時間おきにAIが読み込めるチャンク(分割データ)に変換してMariaDBに保存する。
  • コンテンツの事前生成: 明日の朝配信するメルマガの文章や、ブログ記事のアイキャッチ画像を、深夜のAPIが空いている時間帯(かつ料金が安い場合がある時間帯)に自動生成しておく。
  • サーバーの保守タスク: ユーザーが生成して放置された古い画像データや、巨大化したチャット履歴ログを定期的に削除・圧縮する。

これらの処理をPHPのWebアクセス(Apache経由)で実行しようとすると、PHPの max_execution_time(デフォルト30秒)や、Apacheのタイムアウト設定に引っかかり、処理が途中で強制終了してしまいます。だからこそ、OSのターミナルから直接PHPを実行する「CLI(Command Line Interface)版PHP」とCronの組み合わせが必要なのです。


2. AlmaLinux 9におけるCronの基礎知識

Linuxの標準機能である「Cron(クーロン)」は、指定した日時にコマンドやスクリプトを自動的に実行してくれる常駐プログラム(デーモン)です。
AlmaLinux 9では crond サービスとして稼働しています。まずはサービスが動いているか確認しましょう。

sudo systemctl status crond
# "Active: active (running)" と表示されればOK

Crontabの書き方

Cronの設定は crontab -e コマンドを使って編集します。書式は以下の通りです。

* * * * * 実行するコマンド
┬ ┬ ┬ ┬ ┬
│ │ │ │ │
│ │ │ │ └ 曜日 (0 - 7) (0と7は日曜日)
│ │ │ └─ 月 (1 - 12)
│ │ └─── 日 (1 - 31)
│ └───── 時 (0 - 23)
└─────── 分 (0 - 59)

【設定例】

  • 0 3 * * * /usr/bin/php /var/www/html/batch.php (毎日 深夜3時00分に実行)
  • */15 * * * * /usr/bin/php /var/www/html/batch.php (15分ごとに実行)

⚠️ 初心者が陥りやすいCronの罠
Cronは、あなたが普段ログインしているターミナルとは全く別の環境(環境変数が少ない状態)で実行されます。そのため、コマンドやファイルのパスは、必ず /usr/bin/php/var/www/html/... のように「絶対パス」で記述するのが鉄則です。


3. PHPによるAIバッチスクリプトの実装(CLI環境)

それでは、実際に「データベースに未処理として溜まっている記事データを読み込み、AIに要約させて、結果をデータベースに保存し直す」というPHPバッチスクリプトを作成します。

バッチ用PHPスクリプト(batch_summarize.php)

このスクリプトはWebからアクセスさせる必要がないため、公開ディレクトリ(/var/www/html/)ではなく、安全な場所(例:/var/www/batch/)に配置します。

sudo mkdir -p /var/www/batch
sudo nano /var/www/batch/batch_summarize.php
<?php
// /var/www/batch/batch_summarize.php

// 1. Webブラウザからのアクセスを完全に遮断する(CLIからの実行のみ許可)
if (php_sapi_name() !== 'cli') {
    die("このスクリプトはコマンドラインからのみ実行可能です。\n");
}

// DB接続情報(絶対パスで読み込むこと)
require_once '/var/www/html/db_connect.php';

$api_key = "あなたの_API_KEY";
$api_url = "https://api.example.com/v1/generate";

echo "[" . date('Y-m-d H:i:s') . "] バッチ処理を開始します...\n";

try {
    // 2. 要約がまだ行われていない(statusが0の)記事データを取得(一度に5件ずつ処理)
    $stmt = $pdo->prepare("SELECT id, content FROM articles WHERE status = 0 LIMIT 5");
    $stmt->execute();
    $articles = $stmt->fetchAll();

    if (empty($articles)) {
        echo "[" . date('Y-m-d H:i:s') . "] 処理対象の記事はありませんでした。\n";
        exit;
    }

    foreach ($articles as $article) {
        echo "記事ID: {$article['id']} の要約処理を開始...\n";

        // AI APIへのリクエスト作成
        $prompt = "以下の文章を100文字以内で要約してください。\n\n" . $article['content'];
        
        $post_data = json_encode([
            "model" => "high-performance-model",
            "messages" => [
                ["role" => "system", "content" => "あなたは優秀な編集者です。"],
                ["role" => "user", "content" => $prompt]
            ],
            "temperature" => 0.3
        ]);

        // cURLの実行
        $ch = curl_init($api_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        // バッチ処理なのでタイムアウトは長め(120秒など)に設定できる!
        curl_setopt($ch, CURLOPT_TIMEOUT, 120); 
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $api_key
        ]);

        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($http_code === 200) {
            $result = json_decode($response, true);
            $summary = $result['choices'][0]['message']['content'];

            // 3. AIの要約結果をDBに保存し、ステータスを1(処理済み)に更新
            $update_stmt = $pdo->prepare("UPDATE articles SET summary = ?, status = 1 WHERE id = ?");
            $update_stmt->execute([$summary, $article['id']]);
            echo " -> 成功: 記事ID {$article['id']} の要約を保存しました。\n";
        } else {
            echo " -> エラー: API通信失敗 (HTTP $http_code)\n";
        }

        // 4. 【重要】APIのレート制限に引っかからないよう、処理の間に意図的なディレイ(ウェイト)を入れる
        sleep(2); 
    }

} catch (Exception $e) {
    echo "[" . date('Y-m-d H:i:s') . "] システムエラー: " . $e->getMessage() . "\n";
}

echo "[" . date('Y-m-d H:i:s') . "] バッチ処理が完了しました。\n";
?>

このスクリプトの特徴は、sleep(2) のように処理の間に一時停止を挟んでいる点です。
Webアクセスではこんなことをすればユーザーを怒らせてしまいますが、深夜に裏側で動くバッチ処理なら、ゆっくり確実にAPIを叩き、課金制限やアクセス上限(Rate Limit)を回避することが推奨されます。


4. 第5回の課題解決:古いAI生成画像の自動クリーンアップ

第5回で画像生成AIを組み込んだ際、「サーバー内に生成された画像が溜まり続けるとストレージがパンクする」という課題を残していました。
これをCronとLinuxの強力な find コマンドを使って解決します。

画像の自動削除コマンド

PHPを書かなくても、Linuxのシェルコマンド1行で「X日以上経過したファイルを削除する」ことが可能です。

# 例:/var/www/html/ai_images ディレクトリ内のファイルで、更新日が7日以上前のものを探し出して削除する
find /var/www/html/ai_images -type f -name "*.png" -mtime +7 -delete

これをCronに登録し、毎日深夜4時に自動で大掃除させましょう。


5. 【プロの極意】flockコマンドによる二重起動の完全防止

最後に、プロのインフラエンジニアがバッチ処理を組む際に絶対に欠かさないテクニックを紹介します。
それは「二重起動の防止」です。

コウ君

二重起動?それって何がヤバいんですか?

リナックス先生

想像してみて。
例えば「10分おき」にAI処理バッチをCronで回したとするわね。でも、ある日データが多すぎて、処理が終わるまでに「15分」かかってしまったらどうなる?
1回目の処理が終わる前に、2回目のCronが発動してしまうのよ!

二重起動が発生すると、同じデータに対して同時にAI APIを叩いてしまったり、データベースの更新が競合してデータが破損(デッドロック)したりします。
これを防ぐために、Linuxの flock(ファイルロック)コマンド をCronの記述に組み込みます。

安全なCrontabの最終形態

ターミナルで sudo crontab -e -u apache(Apache権限で実行する場合)と入力し、以下のように登録します。

# 1. AI要約バッチを10分ごとに実行。ただし、実行中はロックファイル(/tmp/ai_batch.lock)を作成し、二重起動を防ぐ。
# 標準出力とエラー出力は /var/log/ai_batch.log に追記する。
*/10 * * * * /usr/bin/flock -n /tmp/ai_batch.lock /usr/bin/php /var/www/batch/batch_summarize.php >> /var/log/ai_batch.log 2>&1

# 2. 古い画像のクリーンアップバッチを毎日深夜4時00分に実行。
0 4 * * * /usr/bin/find /var/www/html/ai_images -type f -name "*.png" -mtime +7 -delete

flock -n を使うことで、「もし既にロックファイルが存在する(=前の処理がまだ動いている)場合は、今回のCronの実行をスキップする」という超安全な運用が可能になります。これが現場のリアルな運用構築術です。


総まとめ:自動化こそがインフラエンジニアの魔法

第7回の解説、お疲れ様でした。

今回は、AlmaLinux 9のCronとPHP-CLIを用いたAIタスクのバッチ処理化、シェルコマンドによるストレージ保守、そしてflockによる二重起動防止を学びました。
これらを駆使することで、あなたのAIアプリケーションはユーザーに見えないところで24時間365日、エラーで倒れることなく黙々と働き続ける「最強のシステム」へと進化しました。

次回はいよいよ最終回、【第8回】実践プロジェクト:独自AIアシスタントWebアプリのデプロイと総まとめ です。
これまで第1回から第7回で学んできた全ての技術(環境構築、プロンプト制御、DB記憶、RAG、画像、セキュリティ、バッチ)を結合し、あなただけのAI Webアプリを完成させましょう!
お楽しみに!LINUX工房の「リナックス先生」でした。

▼ 24時間AIを働かせる安定環境 ▼

Cronやバッチ処理も安定稼働!
「稼働率99.99%の高耐久VPS」

VPSランキングを見る

運用保守・自動化スキルを武器に
「インフラエンジニア特化転職」

転職エージェントを見る

コメント