アイキャッチ画像: デスクの上でパソコンを使用している

本日は Drupal 7 の Queue API についてご紹介してみたいと思います。 今回はちょっと開発者寄りのお話です。

Queue API は、特定の処理を後からまとめて実行できるいわゆる「処理待ちキュー」を提供するためのインタフェースです。 重い処理などを処理の受付タイミングとは別のタイミングに実行できるというすぐれものです。 こんなものまでデフォルトでコアに入っているなんて、 Drupal は(いい意味で)クレイジーです。

今回は Queue API の中でもそれを最も手軽に使える cron queue について取り上げたいと思います。

Drupal の Queue API を使う手順はざっくり言ってしまうと次の 3 ステップです。

  1. キューを作成する
  2. 1 のキューにアイテム(処理)を追加する
  3. 2 のアイテムを実行する

その処理が cron queue を使うことでたった数十行のコードでお手軽に利用できるようになります。 実行タイミングは cron にお任せできるので開発者側でやるべきことは最小限で済みます。

以下具体的な手順をご説明していきます。

  1. hook_cron_queue_info() でキューを定義する
  2. 1 に対応するコールバックを作成する
  3. 1 のキューにアイテムを登録する処理を作成する
  4. 確認

1. hook_cron_queue_info() でキューを定義する

Drupal 開発の他の例にもれず最初のステップは hook 関数の implement です。 今回利用するのはフック関数 hook_cron_queue_info() です。 以下では umi という名前のモジュールが存在するという想定で話を進めていきます。

/**
 * Implements hook_cron_queue_info().
 */
function umi_cron_queue_info() {

  $queues = array();

  // 処理時間の上限を 30 分間とする
  $allowed_seconds = 60 * 30;

  // プロダクトを全件エクスポートするキュー
  $queues['umi_incredible_process'] = array(
    'worker callback' => '_umi_incredibly_heavy_process',
    'time' => $allowed_seconds,
  );

  return $queues;
}

ポイントは worker callbacktime の 2 行です。

worker callback では対象となる処理を行う関数を指定しています。 この記述によって、キューのアイテムが処理されるときに _umi_incredibly_heavy_process という関数が実行されることになります。

time の方は処理にかけてもいい時間の上限値です。 この他にオプションでもうひとつ skip on cron というアイテムを設定することができます。 こちらは cron のときに自動で実行してほしくない場合にのみ指定するものなので今回は置いておきましょう。

キャッシュをクリアすればキューの定義は完了です。

2. 1 に対応するコールバックを作成する

1 で指定した _umi_incredibly_heavy_process() 関数を作成しましょう。

/**
 * これはたいそう重い処理だそうです
 */
function _umi_incredibly_heavy_process($item) {

  // HTTP 経由でデータを取得したりします
  $urls = $item['urls'];
  foreach ($urls as $u) {
    _umi_fetch_heavy_site_data($u);
  }

  // 重いファイルを生成したりもします
  $files = $item['files'];
  foreach ($urls as $u) {
    _umi_generate_heavy_file($u);
  }

  watchdog('umi', '重い処理が実行されました。');
}

ここで重要なのはこのコールバックが $item という引数を受け取るということです。 関数 _umi_fetch_heavy_site_data()_umi_generate_heavy_file() はあくまでも仮想のものです。 とにかく重い処理を実行するイメージです。 watchdog() はログに記録する処理ですが、このあたりも適宜メール送信やその他の通知に適宜変更するとよいでしょう。

$item にどういうデータを放り込むかというのは次のステップ 3 で指定することになります。

3. 1 のキューにアイテムを登録する処理を作成する

キューに実際のアイテムを登録する処理を書きます。 画面経由で登録できるようにする場合は、たとえばフォームのサブミットハンドラは次のようになります。

/**
 * フォームのサブミットハンドラ: 重い処理をキューに登録する
 */
function umi_incredible_process_form_submit($form, &$form_state) {

  $urls = $form_state['values']['urls'];
  $files = $form_state['values']['files'];

  $queue = DrupalQueue::get('umi_incredible_process');

  $item = array(
    'urls' => $urls,
    'files' => $files,
  );
  $queue->createItem($item);

  drupal_set_message('重い処理が登録されました。');
}

個々でのポイントは DrupalQueue::get()DrupalQueue#createItem() のふたつです。 get() でキューを取得し、 createItem() でアイテムをキューに追加します。

追加するアイテムはもちろん _umi_incredibly_heavy_process で想定している $item と同じフォーマットである必要があります。

4. 確認

ここまで来たら後は umi_incredible_process_form() を書くなどして処理をトリガーできるようにして確認するだけです。 次回の cron 実行が無事に終わった後にログに「重い処理が実行されました。」というメッセージが残されていれば確認は完了です。

以上です。 いかがだったでしょうか?

今回は Drupal 7 の Queue API 、中でもそれをもっとも手軽に利用できる hook_cron_queue_info() の利用方法をご紹介いたしました。

かんたんに使えて何かと便利なものなので、リクエスト時には実行したくないような処理が出てきた場合などには利用を検討してみていただければと思います。


共に働く新しい仲間を
募集しています

スタジオ・ウミは「Drupal」に特化したサービスを提供する Drupal のエキスパートチーム。
フルリモート&フレックス制だから、働く場所を選ばず時間の使い方も自由です。
そんなワークライフバランスの整った環境で、当ブログに書かれているような
様々な技術を共に学びながら、Drupalサイト開発に携わってみたい方を募集しています。
まずはお話だけでも大歓迎!ぜひお気軽にご連絡ください。