web-dev-qa-db-ja.com

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

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

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

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

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

19
uwe

これはバッチの仕組みです(私の理解に基づく)

1. 初期化

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

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

バッチプロセス

  1. プロセスを開始するために、Batchはキューを作成し、バッチ配列で定義したすべてのoperations(functions and arguments)を追加します。

    $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. 今回のBatch呼び出しでは、Queueアイテムを1つずつ要求し、それに定義されている引数で定義された関数を実行します。

  3. これは重要な部分です。バッチ操作を実装する関数(操作)は、データをチャンク化し、PHPのメモリ制限、タイムアウト。そうしないと、最終的に問題が発生します。

先日、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が再び開かれたときに再起動しますか?移行モジュールは時々続行されますが、おそらくキューを使用していますか?

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

問題を解決する of PHPタイムアウトは、移行モジュールで利用できるDrushバッチを使用しますが、最初に移行のバッチ関数をDig outして、処理データをチャンク化してみてください。

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

はい、停止します。

同じURLが再び開かれたときに再起動しますか?移行モジュールは時々続行されますが、おそらくキューを使用していますか?

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

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

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

Webインターフェースを介してプロセスを実行する場合、PHP max_execution_time(通常、30秒以上の場合は30秒)が適用されます。したがって、長時間実行されるプロセスでは、分割を管理するバッチAPIを使用する必要があります。つまり、移行プロセスが起動し、25秒ほど実行されてから停止し、Batch APIに、移行プロセスが再開される新しいページリクエストを無限に発行させます。

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

速いです

Batch APIは、多くのオーバーヘッドをもたらします-ページ要求をシャットダウンして再呼び出しし、移行プロセスは必要なすべてのコンストラクターを再度実行する必要があり、データベース接続が再確立され、クエリが再実行されるなどです。また、部分的なインポートの場合、選択する必要があります中断したところまで-最初の500個のソースレコードがインポートされている場合、501番目のレコードを見つける必要があります。ソース形式とその構築方法に応じて、これはスケーリングする場合としない場合があります。SQLソースで最高水準点を使用している場合、クエリ自体が以前のレコードを削除し、中断したところからすぐに開始できます。そうでない場合、Migrateはソースデータをスクロールして、インポートされていない最初のレコードを探す必要があります。たとえば、大きなXMLファイルをソースとして使用すると、何度も繰り返した後、PHP max_execution_timeよりも長い時間がかかる可能性があり、取得できる場所に到達するため、移行が停止する可能性があります。

それはより信頼できる

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

それはより便利です

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

これについての詳細は here を参照してください。

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

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

10
Mathankumar

Batch API を注意深く理解し、これらのモジュールが次のことを支援します。

1 - Progerss これは、進行状況を追跡するための一般的なフレームワークを実装する試みです

2- バックグラウンド進行状況 既存のバッチAPIを引き継ぎ、バックグラウンドプロセスでバッチジョブを実行します

0
Mohammed Gomma