/sites/default/files/2023-10/drush_3200_1800_0.png

Drush выполняет команду или скрипт в одном процессе. Это значит, что выполнение долгих и тяжёлых операций может приводить к утечкам памяти из-за накопления статического кэша. Особенно заметно это проявляется при выполнении CRUD операций для большого числа сущностей, например, при выполнении пакетной обработки (батч). Drush имеет механизм для обработки таких ситуаций в контексте пакетных операций. Если будет израсходовано более 50% доступной памяти, процесс будет перезапущен. Однако в данном случае есть две проблемы:

  1. Защита сработает только при выполнении батча. Если батч не используется, то выполнение продолжится пока не будет израсходована вся доступная память. С одной стороны, это значит, что обработка данных реализована неправильно и должен использоваться батч. С другой стороны, речь может идти об уже реализованных командах, время на рефакторинг которых ещё не выделено. Помимо этого, запускаемый код может находиться в отдельном скрипте и батч там, соответственно, не используется.
  2. На некоторых конфигурациях Drush не может перезапустить процесс и на этом обработка прерывается, не достигнув своего завершения. В идеале данная проблема должна быть решена настройками сервера, однако, при отсутствии такой возможности проблему можно решить программно.

Программное решение предполагает своевременную очистку статического кэша. При использовании батча очистка должна выполняться на каждой операции или раз в несколько операций. Если батч не используется, очистку следует запускать на каждой итерации цикла или раз в несколько итераций.


// Reset static cache when the operation is called from Drush.
// This avoids memory leaks in case of processing a large number of entities.
if (drupal_is_cli() && function_exists('drush_memory_limit')) {
  // Prevent already processed entities from being stored in memory.
  drupal_static_reset('entity_get_controller');

  // Prevent starting a new thread (on some configurations it crashes the
  // whole process). Drush starts new thread after exceeding 50% of
  // available memory. Therefore, reset the entire static cache at ~33%.
  if (drush_memory_limit() > 0 && (memory_get_usage() * 3) >= drush_memory_limit()) {
    drupal_static_reset();
  }
}

Работа решения протестирована для Drupal 7 и Drush 8.

Добавить комментарий