Comment fonctionne l'API batch en interne?

19

J'ai rencontré un problème de dépassement de délai lors de la migration l'autre jour et j'ai commencé à me demander comment l' API Batch fonctionne en interne.

D'après ce que je comprends, dans sa forme la plus simple, vous passerez un tableau de valeurs (nids par exemple) et une fonction pour opérer sur ces valeurs. L'API par lots traite ensuite un nombre fixe de ces valeurs avec chaque demande jusqu'à ce qu'elle soit terminée.

Lorsqu'un lot est en cours d'exécution, la page semble utiliser des requêtes Ajax pour afficher la progression de l'opération par lots (% terminé et messages). Je suppose qu'il attend la fin de la demande pour mettre à jour la progression, puis lancer la prochaine demande immédiatement après?

Si la page contenant la demande de lot est fermée, le traitement par lots s'arrête-t-il? Va-t-il redémarrer lorsque la même URL sera rouverte? Le module de migration continue parfois mais utilise probablement des files d'attente?

uwe
la source

Réponses:

40

Voici comment fonctionne le batch (selon ma compréhension)

1. Initialiser

  1. Initialisez le traitement par lots. Basé sur la configuration des clients (navigateurs) selon que JavaScript est activé ou non.
  2. Les clients compatibles JavaScript sont identifiés par le cookie 'has_js' défini dans drupal.js. Si aucune page compatible JavaScript n'a été visitée pendant la session de navigation de l'utilisateur actuel, la version non JavaScript est renvoyée.
  3. Si JavaScript activé Batch utilise la demande ajax, la connexion reste active sur la demande.
  4. Si JavaScript n'est pas activé, Batch utilise définit une balise META en html pour effectuer des intervalles de rafraîchissement réguliers afin de maintenir la connexion active tout au long de la demande.

(C'est ainsi que la barre de progression est mise à jour sur la progression de la tâche terminée.)

Traitement par lots

  1. Pour démarrer le processus, Batch crée une file d'attente et ajoute toutes les opérations (fonctions et arguments) que vous définissez dans le tableau de commandes comme,

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

    De plus, il attribue également un identifiant de lot unique parmi les lots.

  2. Maintenant, les appels par lots revendiquent les éléments de la file d'attente un par un et exécutent la fonction définie avec les arguments qui y sont définis.

  3. Ceci est une partie cruciale, la fonction (opération) qui implémente l'opération par lots doit fragmenter les données et traiter les données très efficacement en gardant à l'esprit la limite de mémoire de PHP, Time out . Ne pas le faire aboutira à votre problème.

J'ai rencontré un problème de délai d'expiration en utilisant la migration l'autre jour et j'ai commencé à me demander comment l'API batch fonctionne en interne.

La fonction batch

Les fonctions qui implémentent Batch doivent prendre les choses suivantes très attentivement,

  • Nombre d'éléments dans les opérations à traiter, comme

    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}'));
    }
  • Limiter le nombre d'éléments à traiter dans un appel de fonction comme la définition d'une limite,

    // For this example, we decide that we can safely process 5 nodes at a time without a timeout.
    $limit = 5;
  • Mise à jour sur le processus de post-traitement comme,

    // Update our progress information.
        $context['sandbox']['progress']++;
        $context['sandbox']['current_node'] = $node->nid;
        $context['message'] = t('Now processing %node', array('%node' => $node->title));
  • Informer le moteur de batch si le batch est terminé ou pas,

    // 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 plupart des points ci-dessus sont pris en charge les opérations par lots de Drupal Core s'il est manquant dans la fonction de mise en œuvre. Mais il est toujours préférable de définir dans la fonction d'implémentation

Rappel par lots terminé

  • Il s'agit du dernier rappel appelé lorsqu'il est défini dans le tableau de commandes. Habituellement, un rapport sur la quantité traitée, etc.

RÉPONSES

Si la page contenant la demande de lot est fermée, le traitement par lots s'arrête-t-il? Va-t-il redémarrer lorsque la même URL sera à nouveau ouverte? Le module de migration continue parfois mais utilise probablement des files d'attente?

Oui, idéalement, il devrait redémarrer le lot et, comme indiqué ci-dessus, il est basé sur la fonction que vous implémentez.

Pour résoudre votre problème de PHP Time out, utilisez Drush batch qui est disponible dans le module migrate, mais commencez par déterrer les fonctions batch de migrate et essayez de fragmenter vos données de traitement.

Dinesh Kumar Sarangapani
la source
1
Superbe promenade. Je voudrais également souligner que le lot commence à être traité pendant ce qui, pour l'utilisateur au moins, semble être la "Initialisation". écran. Autrement dit, s'il faut 4 secondes pour configurer et 10 secondes pour traiter le premier élément du lot, l'utilisateur verra le processus «Initialisation». pendant quatorze secondes dans cet exemple. Cela a du sens, car le premier message d'écran non initialisé est "n terminé", ce qui ne fonctionnerait qu'après le traitement de certains. Si c'est faux, corrigez-moi s'il vous plaît!
texas-bronius
Aussi, d'après mon expérience. Si vous quittez la page, l'opération par lots / bloc en cours consommera toujours des ressources jusqu'à ce qu'elle soit terminée. Il ne lance plus la tâche par lots, mais complète la tâche en cours.
Elijah Lynn
10

Si la page contenant la demande de lot est fermée, le traitement par lots s'arrête-t-il?

Oui, il sera arrêté.

Va-t-il redémarrer lorsque la même URL sera à nouveau ouverte? Le module de migration continue parfois mais utilise probablement des files d'attente?

Comme l'a dit Dinesh, cela dépend de la mise en œuvre.

Vous devez exécuter la migration à l'aide de drush, car

Drush s'exécute sur la ligne de commande et n'est soumis à aucune limite de temps (en particulier, max_execution_time de PHP ne s'applique pas). Ainsi, lorsque vous démarrez un processus de migration exécuté via drush, il démarre simplement et continue de fonctionner jusqu'à ce qu'il soit terminé.

Lors de l'exécution de processus via une interface Web, le PHP max_execution_time (généralement 30 secondes sinon moins) s'applique. Ainsi, pour les processus de longue durée, nous devons utiliser l'API Batch, qui gère la décomposition d'un processus sur plusieurs demandes. Ainsi, un processus de migration démarre, s'exécute pendant environ 25 secondes, puis s'arrête et laisse l'API Batch émettre une nouvelle demande de page, dans laquelle le processus de migration est redémarré, à l'infini.

Donc, en comprenant cela, pourquoi Drush est-il meilleur?

C'est plus rapide

L'API Batch introduit de nombreux frais généraux - arrêt et réinvocation des demandes de page, le processus de migration doit à nouveau passer par tous les constructeurs nécessaires, les connexions à la base de données sont rétablies et les requêtes sont réexécutées, etc. Et, pour une importation partielle, il doit sélectionner là où il s'était arrêté - si les 500 premiers enregistrements source ont été importés, il doit trouver le 501e enregistrement. En fonction de votre format source et de la façon dont il est construit, cela peut ou non évoluer - si vous utilisez des marques hautes avec une source SQL, la requête elle-même peut éliminer les enregistrements précédents et commencer là où vous vous étiez arrêté. Sinon, Migrate doit faire défiler les données source à la recherche du premier enregistrement non importé. Avec, disons, un gros fichier XML comme source,

C'est plus fiable

L'exécution de migrations via votre navigateur ajoute votre bureau et votre connexion Internet locale comme points de défaillance. Un problème réseau lorsque l'API Batch passe à la demande de page suivante, un plantage du navigateur, une fermeture accidentelle du mauvais onglet ou de la mauvaise fenêtre peuvent tous interrompre votre migration. L'exécution en drush réduit les pièces mobiles - vous éliminez votre bureau et votre connexion Internet locale comme facteurs.

C'est plus utile

Si quelque chose ne va pas lors de l'exécution dans Drush, s'il y a des messages d'erreur utiles, vous les verrez. Les échecs à l'aide de l'API Batch sont souvent engloutis et tout ce que vous voyez est complètement inutile "Une requête HTTP AJAX s'est terminée anormalement. Des informations de débogage suivent. Chemin: / batch? Id = 901 & op = do StatusText: ResponseText: ReadyState: 4".

Vous pouvez trouver plus d'informations à ce sujet ici .

En attendant, si vous souhaitez exécuter le lot même si la fenêtre du navigateur est fermée, envisagez le module Processus d'arrière-plan . Il dispose d'un sous - module Batch Background qui fait l'affaire.

Ce module prend en charge l'API Batch existante et exécute des travaux par lots dans un processus d'arrière-plan. Cela signifie que si vous quittez la page de lot, les travaux se poursuivent et vous pouvez revenir à l'indicateur de progression ultérieurement.

Mathankumar
la source
wow, utiliser drush pour migrer a fait une énorme amélioration. Je dois migrer vers un site en direct et cela met beaucoup moins de charge sur le système! Je vous remercie!
uwe
0

Comprenez bien l' API Batch et ces modules vous aideront à:

1- Progerss Il s'agit d'une tentative de mise en œuvre d'un cadre générique pour garder une trace de tout progrès

2- La progression en arrière-plan prend le contrôle de l'API Batch existante et exécute des travaux par lots dans un processus en arrière-plan

Mohammed Gomma
la source