バッチAPIは内部的にどのように機能しますか?


19

先日、migrateを使用してタイムアウトの問題に遭遇し、Batch APIが内部でどのように機能するのか疑問に思い始めました。

私がそれを理解する方法は、最も単純な形式で、値の配列(nidなど)とそれらの値を操作する関数を渡すことです。次に、バッチAPIは、完了するまで各リクエストでこれらの値の固定数を処理します。

バッチが実行されているとき、ページはAjaxリクエストを使用してバッチ操作の進行状況(%doneおよびmessages)を表示しているようです。リクエストが進行状況の更新を完了するまで待機し、その後すぐに次のリクエストを開始すると想定していますか?

バッチリクエストのあるページが閉じている場合、バッチ処理は停止しますか?同じURLを再度開いたときに再起動しますか?移行モジュールは継続する場合がありますが、おそらくキューを使用していますか?

回答:


40

これがバッチの仕組みです(私の理解に基づいて)

1. 初期化

  1. バッチ処理を初期化します。JavaScriptが有効かどうかのクライアント(ブラウザ)設定に基づきます。
  2. JavaScript対応クライアントは、drupal.jsで設定された「has_js」Cookieによって識別されます。現在のユーザーのブラウザセッション中にJavaScript対応のページにアクセスしていない場合、JavaScript以外のバージョンが返されます。
  3. JavaScript対応の Batchがajaxリクエストを使用する場合、リクエスト全体で接続を維持します。
  4. JavaScriptが有効になっていない場合 Batchはhtmlにメタタグを設定して、定期的に更新間隔を設定し、リクエスト全体で接続を維持します。

(これは、ジョブ完了の進行状況で進行状況バーが更新される方法です。)

バッチ処理

  1. プロセスを開始するために、Batchはキューを作成し、次のようなバッチ配列で定義したすべての操作(関数と引数)を追加します。

    $batch = array (
    'operations' => array(
      array('batch_example_process', array($options1, $options2)),
      array('batch_example_process', array($options3, $options4)),
      ),
    'finished' => 'batch_example_finished',
    'title' => t('Processing Example Batch'),
    'init_message' => t('Example Batch is starting.'),
    'progress_message' => t('Processed @current out of @total.'),
    'error_message' => t('Example Batch has encountered an error.'),
    'file' => drupal_get_path('module', 'batch_example') . '/batch_example.inc',
    );

    さらに、バッチ全体で一意のバッチIDも割り当てます。

  2. これで、バッチ呼び出しはキュー項目を1つずつ要求し、定義されている引数で定義された関数を実行します。

  3. これは重要な部分です。バッチ操作を実装するfunction(Operation)は、PHPのメモリ制限Time outを考慮して、データをチャンクし、データを非常に効率的に処理する必要があります。そうしないと、問題が発生します。

先日、migrateを使用してタイムアウトの問題に遭遇し、バッチAPIが内部でどのように機能するのか疑問に思い始めました。

バッチ機能

Batchを実装する関数は、次のことを非常に慎重に行う必要があります。

  • 操作内のアイテムの数は、

    if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['current_node'] = 0;
    $context['sandbox']['max'] = db_result(db_query('SELECT COUNT(DISTINCT nid) FROM {node}'));
    }
  • 制限の設定など、1回の関数呼び出しで処理するアイテムの数を制限する、

    // For this example, we decide that we can safely process 5 nodes at a time without a timeout.
    $limit = 5;
  • 次のような後処理へのプロセスの更新、

    // Update our progress information.
        $context['sandbox']['progress']++;
        $context['sandbox']['current_node'] = $node->nid;
        $context['message'] = t('Now processing %node', array('%node' => $node->title));
  • バッチが完了したかどうかをバッチエンジンに通知する、

    // Inform the batch engine that we are not finished,
    // and provide an estimation of the completion level we reached.
    if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
     }

上記のポイントのほとんどは、実装機能で欠落している場合、Drupalのコアバッチ操作を処理します。ただし、実装関数で定義することは常に最適です

バッチ終了コールバック

  • これは、バッチ配列で定義されたときに呼び出される最後のコールバックです。通常は、処理量などのレポートです。

回答

バッチリクエストのあるページが閉じている場合、バッチ処理は停止しますか?同じURLを再度開いたときに再起動しますか?移行モジュールは継続する場合がありますが、おそらくキューを使用していますか?

はい、理想的には、バッチを再起動する必要があり、上記のように、実装する機能に基づいています。

PHPタイムアウトの問題解決するには、移行モジュールで利用可能なDrushバッチを使用しますが、最初に移行のバッチ機能を掘り下げて、処理データをチャンクしようとします。


1
素晴らしいウォークスルー。また、少なくともユーザーには「初期化中」と思われる処理中にバッチが処理を開始することを指摘したいと思います。画面。つまり、セットアップに4秒、最初のバッチアイテムの処理に10秒かかる場合、ユーザーには「初期化中」というプロセスが表示されます。この例では14秒間です。これは、最初の非初期化画面メッセージが「n完了」であり、一部が処理された後にのみ機能するため、意味があります。これが間違っている場合は、修正してください!
テキサスブロニウス

また、私の経験から。ページを離れると、処理中のバッチ操作/チャンクは、完了するまでリソースを消費します。バッチジョブはそれ以上実行されませんが、現在のバッチジョブは完了します。
イライジャ・リン

10

バッチリクエストのあるページが閉じている場合、バッチ処理は停止しますか?

はい、停止します。

同じURLを再度開いたときに再起動しますか?移行モジュールは継続する場合がありますが、おそらくキューを使用していますか?

Dineshが言ったように、それは実装に依存します。

drushを使用して移行を実行する必要があります。

Drushはコマンドラインで実行され、時間制限はありません(特に、PHPのmax_execution_timeは適用されません)。そのため、drushを使用して実行する移行プロセスを開始すると、単に起動し、完了するまで実行を続けます。

Webインターフェースを介してプロセスを実行する場合、PHPのmax_execution_time(通常、少なくとも30秒)が適用されます。したがって、長時間実行されるプロセスの場合、複数のリクエストにまたがるプロセスの分割を管理するバッチAPIを使用する必要があります。そのため、移行プロセスが開始され、25秒程度実行された後、停止され、バッチAPIが新しいページリクエストを発行し、移行プロセスが無限に再起動されます。

だから、それを理解して、なぜDrushが優れているのですか?

速いです

バッチAPIは多くのオーバーヘッドをもたらします-シャットダウンしてページリクエストを再度呼び出し、移行プロセスは必要なすべてのコンストラクターを再度実行する必要があり、データベース接続は再確立され、クエリは再実行されます。最初の500個のソースレコードがインポートされた場合、501番目のレコードを見つける必要があります。ソース形式とその構成方法に応じて、これはスケーリングされる場合とされない場合があります。SQLソースで最高水準点を使用している場合、クエリ自体は以前のレコードを削除し、中断したところから開始できます。そうでない場合、Migrateはソースデータをスクロールして、インポートされていない最初のレコードを探します。たとえば、大きなXMLファイルをソースとして使用すると、

より信頼性が高い

ブラウザから移行を実行すると、デスクトップとローカルインターネット接続が障害ポイントとして追加されます。Batch APIが次のページリクエストに移動しているときのネットワークの不具合、ブラウザのクラッシュ、誤ったタブまたはウィンドウの偶発的なクローズはすべて、移行を中断する可能性があります。急いで実行すると、可動部分が減ります-デスクトップおよびローカルインターネット接続を要因として排除します。

もっと役立つ

Drushで実行中に何か問題が発生した場合、有用なエラーメッセージがあれば、それらが表示されます。バッチAPIを使用した失敗はしばしば飲み込まれ、完全に役に立たない「AJAX HTTPリクエストが異常終了しました。デバッグ情報が続きます。パス:/ batch?id = 901&op = do StatusText:ResponseText:ReadyState:4 "

詳細については、こちらをご覧ください

それまでの間、ブラウザウィンドウが閉じていてもバッチを実行する場合は、バックグラウンドプロセスモジュールを検討してください。トリックを行うサブモジュールBackground Batchがあります。

このモジュールは、既存のバッチAPIを引き継ぎ、バックグラウンドプロセスでバッチジョブを実行します。つまり、バッチページを離れてもジョブは続行され、後で進行状況インジケーターに戻ることができます。


うわー、drushを使用して移行すると、大幅に改善されました。ライブサイトに移行する必要があり、システムへの負荷が大幅に軽減されます。ありがとうございました!
-uwe

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.