¿Cómo funciona internamente la API por lotes?


19

Me encontré con un problema de tiempo de espera usando migrate el otro día y comencé a preguntarme cómo funciona internamente la API de Batch .

Según tengo entendido, en su forma más simple pasará una matriz de valores (nids, por ejemplo) y una función para operar con esos valores. La API por lotes procesa un número fijo de esos valores con cada solicitud hasta que finaliza.

Cuando se ejecuta un lote, la página parece usar solicitudes de Ajax para mostrar el progreso de la operación por lotes (% completado y mensajes). ¿Supongo que espera hasta que la solicitud haya finalizado para actualizar el progreso y luego comience la siguiente solicitud inmediatamente después?

Si la página con la solicitud de lote está cerrada, ¿se detiene el procesamiento por lotes? ¿Se reiniciará cuando se abra nuevamente la misma URL? ¿El módulo de migración a veces continúa pero probablemente está usando colas?

Respuestas:


40

Así es como funciona el lote (Basado en mi entendimiento)

1. Inicializar

  1. Inicializar el procesamiento por lotes. Según la configuración de los clientes (navegadores) sobre si JavaScript está habilitado o no.
  2. Los clientes habilitados para JavaScript se identifican mediante la cookie 'has_js' establecida en drupal.js. Si no se ha visitado ninguna página habilitada para JavaScript durante la sesión del navegador del usuario actual, se devuelve la versión que no es JavaScript.
  3. Si JavaScript habilitado, Batch usa la solicitud ajax, mantendrá viva la conexión en toda la solicitud.
  4. Si JavaScript no está habilitado, Batch usa establece una metaetiqueta en html para realizar intervalos de actualización regulares para mantener viva la conexión en toda la solicitud.

(Así es como se actualiza la barra de progreso en el progreso del Trabajo realizado).

Proceso por lotes

  1. Para comenzar el proceso, Batch crea una Cola y agrega todas las operaciones (funciones y argumentos) que defina en la matriz de lotes como,

    $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',
    );

    Además, también asigna una identificación de lote que es única en todos los lotes.

  2. Ahora Batch llama a reclamar los elementos de la cola uno por uno y ejecuta la función definida con los argumentos que se definen en él.

  3. Esta es una parte crucial, la función (Operación) que implementa la operación por lotes debe fragmentar los datos y procesar los datos de manera muy eficiente teniendo en cuenta el límite de memoria de PHP, Tiempo de espera . De lo contrario, terminará en su problema.

Me encontré con un problema de tiempo de espera usando migrate el otro día y comencé a preguntarme cómo funciona internamente la API por lotes.

La función de lote

Las funciones que implementan Batch deben tomar las siguientes cosas con mucho cuidado,

  • Número de elementos dentro de las operaciones para procesar como,

    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}'));
    }
  • Limitar el número de elementos para procesar en una llamada de función, como configurar un límite,

    // For this example, we decide that we can safely process 5 nodes at a time without a timeout.
    $limit = 5;
  • Actualización sobre el proceso de postprocesamiento como,

    // Update our progress information.
        $context['sandbox']['progress']++;
        $context['sandbox']['current_node'] = $node->nid;
        $context['message'] = t('Now processing %node', array('%node' => $node->title));
  • Informar al motor de Batch si el Batch está completo o no,

    // 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'];
     }

La mayoría de los puntos anteriores se ocupan de las operaciones por lotes del núcleo de Drupal si se pierde en la función de implementación. Pero siempre es mejor definir en la función de implementación

Devolución de llamada terminada por lotes

  • Esta es la última llamada devuelta cuando se define en la matriz de lotes. Generalmente, un informe de cuánto procesado, etc.

RESPUESTAS

Si la página con la solicitud de lote está cerrada, ¿se detiene el procesamiento por lotes? ¿Se reiniciará cuando se vuelva a abrir la misma URL? ¿El módulo de migración a veces continúa pero probablemente está usando colas?

Sí, idealmente debería reiniciar el lote y, como se dijo anteriormente, se basa en la función que implemente.

Para resolver su problema de tiempo de espera de PHP, use el lote de Drush que está disponible en el módulo de migración, pero primero desenterre las funciones de lote de migrate e intente fragmentar sus datos de procesamiento.


1
Excelente recorrido. También me gustaría señalar que el lote comienza a procesarse durante lo que, al menos para el usuario, parece ser la "Inicialización". pantalla. Es decir, si toma 4 segundos para configurar y 10 segundos para procesar el primer artículo del lote, entonces el usuario verá el proceso "Inicializando". durante catorce segundos en este ejemplo. Esto tiene sentido porque el primer mensaje de pantalla que no es init es "n completado", que solo funcionaría después de que se procesen algunos. Si esto está mal, ¡corrígeme!
texas-bronius

Además, desde mi experiencia. Si abandona la página, la operación por lotes / fragmento que está en proceso seguirá consumiendo recursos hasta que se haya completado. No dispara más del trabajo por lotes, pero completa el actual.
Elijah Lynn

10

Si la página con la solicitud de lote está cerrada, ¿se detiene el procesamiento por lotes?

Sí, se detendrá.

¿Se reiniciará cuando se vuelva a abrir la misma URL? ¿El módulo de migración a veces continúa pero probablemente está usando colas?

Como dijo Dinesh, depende de la implementación.

Debería ejecutar la migración usando drush, porque

Drush se ejecuta en la línea de comando y no está sujeto a ningún límite de tiempo (en particular, no se aplica max_execution_time de PHP). Entonces, cuando comienza un proceso de migración que se ejecuta a través de drush, simplemente se inicia y continúa ejecutándose hasta que finaliza.

Cuando se ejecutan procesos a través de una interfaz web, se aplica PHP max_execution_time (generalmente 30 segundos, si no menos). Por lo tanto, para procesos de larga duración, necesitamos utilizar la API de Batch, que gestiona la división de un proceso en múltiples solicitudes. Por lo tanto, se iniciará un proceso de migración, se ejecutará durante 25 segundos más o menos, luego se detendrá y dejará que la API de Batch emita una nueva solicitud de página, en la que se reinicie el proceso de migración, hasta el infinito.

Entonces, entendiendo eso, ¿por qué es mejor Drush?

Es mas rapido

La API de Batch introduce una gran cantidad de gastos generales: al cerrar y volver a invocar las solicitudes de página, el proceso de migración debe ejecutarse nuevamente a través de todos los constructores necesarios, se restablecen las conexiones de la base de datos y se vuelven a ejecutar las consultas, etc. Y, para una importación parcial, debe elegir donde se quedó: si se importaron los primeros 500 registros de origen, debe encontrar el registro 501. Dependiendo de su formato de origen y de cómo se construya, esto puede escalar o no: si está utilizando marcas de aguas altas con un origen de SQL, la consulta misma puede eliminar los registros anteriores y comenzar justo donde lo dejó. De lo contrario, Migrate debe desplazarse por los datos de origen en busca del primer registro no importado. Con, digamos, un gran archivo XML como fuente,

Es mas confiable

La ejecución de migraciones a través de su navegador agrega su escritorio y su conexión a Internet local, como puntos de falla. Una falla en la red cuando Batch API se mueve a la siguiente solicitud de página, un bloqueo del navegador, un cierre accidental de la pestaña o ventana incorrecta pueden interrumpir su migración. Correr en seco reduce las partes móviles: elimina el escritorio y la conexión a Internet local como factores.

Es más útil

Si algo sale mal cuando se ejecuta en Drush, si hay algún mensaje de error útil, los verá. Las fallas al usar la API de Batch a menudo se tragan y todo lo que puede ver es completamente inútil "Una solicitud HTTP de AJAX finalizó de manera anormal. Sigue la información de depuración. Ruta: / batch? Id = 901 & op = do StatusText: ResponseText: ReadyState: 4".

Puede encontrar más información sobre esto aquí .

Mientras tanto, si desea ejecutar el lote incluso si la ventana del navegador está cerrada, considere el módulo Proceso en segundo plano . Tiene un submódulo Background Batch que hace el truco.

Este módulo se hace cargo de la API de Batch existente y ejecuta trabajos por lotes en un proceso en segundo plano. Esto significa que si sale de la página por lotes, los trabajos continúan y puede volver al indicador de progreso más adelante.


wow, usar drush para migrar hizo una gran mejora. ¡Tengo que migrar a un sitio en vivo y pone mucha menos carga en el sistema! ¡Gracias!
Uwe

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.