タグアーカイブ データベース肥大化

WooCommerce HPOSが48時間で100万件以上のアクションスケジューラ完了ジョブを生成した原因と対処法

WooCommerce HPOSが48時間で100万件以上のアクションスケジューラ完了ジョブを生成した原因と対処法

WooCommerceサイトでデータベースサイズが突然急増し、wp_actionscheduler_actionsテーブルに数百万件もの完了済みジョブが蓄積している場合、HPOSデータ同期バッチプロセスが無限ループを起こしている可能性が極めて高い。ここでは症状の見分け方から原因の特定、停止、クリーンアップまで、具体的な手順をまとめる。

HPOS関連のデータベース肥大化が疑われる症状

HPOS関連のデータベース肥大化が疑われる症状

以下のような兆候が複数同時に現れたら、Action Schedulerの暴走を疑ってよい。

  • データベース容量が短時間で急激に増加する(数GB単位)
  • PHPエラーログのファイルサイズが異常に大きくなる
  • データベースのロックエラーやデッドロックが頻発する
  • 管理画面やフロントエンドで「INSERT command denied」などのエラーが出る
  • サーバーのバックグラウンドプロセスがほぼ常時稼働し続ける
  • 注文件数が数百件なのにAction Schedulerテーブルだけが肥大化している

これらの症状は、単体では他の原因もあり得るが、データベース内の完了ジョブが異常に増えている点が最大の特徴だ。

正常時(Before)
wp_actionscheduler_actions テーブルに数百件程度のジョブが存在する
暴走時(After)
100万件以上の完了ジョブが蓄積し、データベース全体が膨張する
正常時  暴走時

Action Schedulerが暴走していないか確認する方法

Action Schedulerが暴走していないか確認する方法

まずはデータベースを直接調べ、どのジョブが何件蓄積しているかを確かめる。WP-CLIが使えるならコマンドラインから、そうでなければphpMyAdminやAdminerで以下のクエリを実行する。

STEP 1 Action Schedulerテーブルの完了ジョブ数を集計する
STEP 2 フック名「wc_run_batch_process」でフィルタし、引数を確認する
STEP 3 注文件数とジョブ件数を比較し、異常な乖離を確認する
STEP 4 実行中のジョブが1件完了するたびに次が即座にスケジュールされるループを特定する

完了ジョブの数とフック名を調べる

データベースに直接問い合わせる場合、以下のSQLで完了状態のジョブをフック名別に集計できる。

SELECT hook, COUNT(*) AS cnt
FROM wp_actionscheduler_actions
WHERE status = 'complete'
GROUP BY hook
ORDER BY cnt DESC
LIMIT 10;

ここで wc_run_batch_process の件数が数十万〜数百万件と突出していれば、疑いは濃厚だ。

引数(args)から発行元を特定する

次に、そのフックの引数を見る。例えば以下のクエリで先頭の数件を取得する。

SELECT action_id, args, scheduled_date_gmt
FROM wp_actionscheduler_actions
WHERE hook = 'wc_run_batch_process'
AND status = 'complete'
ORDER BY action_id DESC
LIMIT 5;

引数フィールドにはシリアライズされたデータが入っている。その中に Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer という文字列が含まれていれば、HPOSのデータ同期機構がバッチを発行している証拠だ。

注文件数との比較で異常を確信する

管理画面のWooCommerce → 注文で表示される注文の総数は、データベースの wp_posts(またはHPOS有効時は wp_wc_orders)で確認できる。注文が600件しかないのに、同期バッチの完了ジョブが100万件もあるなら、明らかにループが発生している。

動作中のループをリアルタイムで観察する

WP-CLIが利用可能なら、以下のコマンドでペンディング状態のジョブを監視する。

wp action-scheduler list --hook=wc_run_batch_process --status=pending

定期的に実行すると、常に1件だけ存在し、それが完了するとすぐに新たなペンディングが生まれるパターンが観測できるはずだ。これはキューが滞留しているのではなく、バッチ自身が次をスケジュールし続ける無限ループであることを示す。

なぜHPOS DataSynchronizerが無限ループを起こすのか

なぜHPOS DataSynchronizerが無限ループを起こすのか

HPOS(High-Performance Order Storage)を有効にすると、WooCommerceは注文データを従来の wp_posts テーブルから専用テーブルへ移行する。この移行やデータの同期を担うのが DataSynchronizer であり、バックグラウンドでバッチ処理を走らせる。

通常は同期が完了すればバッチは停止するが、何らかの設定不整合やエラーにより「同期が完了したと見なされず、次のバッチが即座に予約される」状態に陥ることがある。具体的には、各バッチが「保留中 → 完了 → 次バッチ予約」というサイクルを際限なく繰り返す。注文数が少なくても、このループによってAction Schedulerのテーブルだけが急激に肥大化し、データベース全体を圧迫する。

保留中(Pending)
完了(Complete)
次バッチ予約(Schedule Next)
再び 保留中(Pending)へ
↑ 無限にループする

このループが起きているかどうかは、データベースを直接見るまで気づきにくい。キャッシュやRedis、WP Rocketなどを最初に疑いがちだが、真因はAction Schedulerの中にある。

データベースの安静化とクリーンアップの手順

データベースの安静化とクリーンアップの手順

原因がHPOSの同期バッチループと判明したら、ループを止め、完了ジョブを削除し、再発を防ぐ。以下の手順を順に実行する。

STEP 1 WP-CLIで同期状態を確認し、必要に応じて同期をリセットする
STEP 2 Action Schedulerの完了ジョブを安全に一括削除する
STEP 3 データベーステーブルを最適化し、容量を解放する
STEP 4 再発防止のためにHPOS設定を見直す

同期状態のリセット

まず、現在のHPOS同期状況を確認する。WP-CLIで次のコマンドを実行する。

wp wc hpos sync status

ここで「status: in-progress」や「pending」が表示される場合、同期が完了しておらず、バッチが動き続けている可能性がある。強制的にリセットし、不要な同期を停止するには以下を実行する。

wp wc hpos sync reset

リセット後、再度ステータスを確認し「idle」や「complete」になっていれば、新たなバッチはスケジュールされなくなる。

完了ジョブの一括削除

100万件単位の完了ジョブを削除するには、Action Schedulerが提供するWP-CLIコマンドを使うのが安全で高速だ。以下のコマンドで、完了状態のジョブをすべて削除できる。

wp action-scheduler clean --status=complete

特定のフックのみを削除したい場合は、プレーンなSQLで一度に削除してもよいが、必ず事前にデータベース全体のバックアップを取ること。

DELETE FROM wp_actionscheduler_actions
WHERE hook = 'wc_run_batch_process' AND status = 'complete';

さらに、関連するログテーブル(wp_actionscheduler_logs)の不要レコードも合わせて削除すると、ディスク容量を大きく回復できる。ただし、こちらは慎重に扱う必要があるため、まずは完了ジョブの削除だけでも効果は大きい。

テーブル最適化で容量を解放

大量のレコードを削除した後は、データベースが断片化し、実際の容量が解放されないことがある。phpMyAdminなどから該当テーブルに対して「最適化(OPTIMIZE TABLE)」を実行するか、以下のSQLを流す。

OPTIMIZE TABLE wp_actionscheduler_actions;
OPTIMIZE TABLE wp_actionscheduler_logs;

これにより、削除した領域がOSに返却され、データベース全体のサイズが縮小する。

再発防止とHPOS設定の見直し

ループが再発しないように、WooCommerceのHPOS設定を確認する。管理画面の WooCommerce → 設定 → 詳細設定 → 機能 から「High-performance order storage(高性能注文ストレージ)」が有効になっているか、そして「互換モードを有効にする」や「データ同期を有効にする」オプションがどのようになっているかをチェックする。

既に全注文がHPOSテーブルに完全移行済みで、互換モードが不要なら、これらの同期オプションを無効化することで、バックグラウンドのバッチ処理そのものを止められる。ただし、テーマやプラグインが古い注文データ参照方法を使っている場合は注意が必要だ。

また、WP-CLIのcronを定期的に監視し、Action Schedulerのジョブ数が異常増加していないかをチェックする仕組みをサーバー監視に組み込むと早期発見につながる。

よくある質問

HPOSが有効かどうかはどこで確認できるか

管理画面の「WooCommerce → 設定 → 詳細設定 → 機能」に移動し、「注文データストレージ」の項目で「High-performance order storage」が選択されていれば有効だ。WP-CLIでは wp wc hpos status で確認できる。

完了ジョブを削除してもサイト動作に影響はないか

Action Schedulerの完了ジョブは過去の処理履歴であり、削除しても現在予約されているジョブや進行中の処理には影響しない。ただし、監査やデバッグ目的で残したい場合は、削除前にバックアップを取ることを強く推奨する。

WP-CLIが使えないレンタルサーバーではどうすればよいか

phpMyAdminなどのデータベース管理ツールから直接SQLで削除できる。プラグイン「WP Crontrol」などを利用すれば、Action Schedulerの一覧を管理画面で確認し、フックごとに手動で削除することも可能だが、件数が多い場合はSQLのほうが現実的だ。

同期をリセットしてもループが再発するのはなぜか

根本原因が解消されていないと再発する。たとえば、同期オプションが有効なまま残っていたり、カスタムコードがバッチをトリガーし続けているケースがある。同期の完全停止を試み、プラグインの干渉も疑いながら一つずつ切り分ける必要がある。

この記事のポイント

  • データベースの急激な肥大化とAction Schedulerの完了ジョブ数に注目する
  • フック名「wc_run_batch_process」と引数からHPOSの同期バッチループを特定する
  • WP-CLIで同期状態をリセットし、完了ジョブを一括削除してテーブルを最適化する
  • HPOSの同期設定を見直し、不要なバッチ処理を完全に止めて再発を防ぐ