Pull to refresh

Comments 16

Много. Информативно. С примерами. Дабл пост не нужен был и вовсе.
Callback операции в качестве последнего аргумента должен принимать по ссылке переменную &$context.

В принципе нет нужды как у Вас через цикл создавать отдельную операцию для каждой ноды.
Корректнее будет передать в операцию весь массив а в конце выполнения операции устанавливать значение $context['finished'] равное количеству обработанных нод деленному на общую длину массива. Прогресс можно сохранять в массиве $context['sandbox']. Операция будет автоматически вызываться до тех пор пока $context['finished'] не примет в качестве значения единицу.

Такой подход лучше
1. С точки зрения идеологии и эстетики: т.к. в батче по хорошему должна быть 1 колбэк — 1 операция (За очень редким исключением. Допустим если надо выполнить операцию А потом Б а потом сново А например)
2. С точки зрения производительности. Батч сохраняет последовательность операций в БД. А теперь представьте что у Вас рабочая ситуация и ноды достаются из БД в количестве 100500+ штук. Вот у Вас и запишется в ячейку 100500+ операций. А на самом деле нужно записать только 1.
А можно пример? А то с батч не работал, ваши слова звучат умно, но не совсем понятно :(
Надо учесть, что для batch в браузере должна быть открыта страница с запущенной задачей, что не всегда приемлемо, в этом случае лучше юзать очереди.
Пример нужен более подробный, у вас очень кратко.
Основная мысль batch — постоянный вызов обработчика для работы над списком задач. То есть нужно показать как брать и сохранять состояния.
Приведу пример с рабочего проекта (сокращённый), импорт юзеров: pastebin.com/GHkVsaJi
UFO just landed and posted this here
Очень нелогичный пример кмк.

В данном случае лучше было не плодить батч-операции, а сохранять смещение в контексте и использовать одну операцию, в которой смотреть номер шага и брать $nid по смещению (в большинстве случаев это будет SELECT… LIMIT x, y). Разные операции обычно используются для разных действий. Например, resave_node и resave_users — это 2 операции, и каждая операция выполняется в несколько шагов.
3 коммент сверху :)
>сохранять смещение в контексте и использовать одну операцию, в которой смотреть номер шага и брать $nid по смещению
Можно по подробнее, пожалуйста?
Представьте что у Вас есть некоторый запрос $sql через который вы получаете массив nid с которыми надо что-то сделать. Тогда перед установкой батча Вы делаете count query к этому запросу получая объем выборки $total. Передаете его в качестве аргумента в операцию.

В самой операции делаете свой запрос $sql с LIMIT $a,$a+$k где
$a — то сколько вы нод уже обработали (отступ)
$k — сколько нод вы хотите обрабатывать за одну итерацию (так чтобы итерация занимала приемлимое для Вас время, например 10 секунд)

Потом идет что-то типо такого блока
if ($a + $k >= $total) {
  $context['finished'] = 1;
}
else {
// Тут сохраняем отступ и достаем его потом в начале следущей итерации
  $context['sandbox']['offset'] = $a + $k;
// Эта штука показывает прогресс. Принимает значения [0;1].
  $context['finished'] = ($a + $k) / $total;
}


Таким образом операция будет выполняться пока $context['finished'] не станет 1 при этом сообщая батчу о прогрессе после каждой итерации. Обратите внимание на то, что $context['sandbox'] не переходит между операциями.
А есть примеры/ссылки на саму технику (чтобы реализовать самому такую технологию)? Уж очень не охота в исходниках копаться.
Концепция довольно проста.
Когда вы устонавливаете задание для батч, задание помещается в БД.
Затем происходит переход на страницу с JavaScript кодом который начинает делать последовательные асинхронные запросы на сервер (в друпал к странице example.com/batch) передавая в качестве одного из параметров ID задания.
Сервер выполняет часть этого задания (одну операцию или одну одну итерацию) и возвращает назад либо сообщение о том что перация выполнена либо процент выполнения.

Таким образом вся магия заключается в том, что большое задание разбивается на несколько этапов и соотвествено несколько запросов, позволяя избежать при этом превышения максимального времени выполнения скрипта.
Минус всего этого заключается в том, что при закрытии страничке в браузере с выполняющимся заданием работа механизма прекращается т.к. некому становиться посылать запросы на сервер. Этот эффект можно немного смягчить, если спланировать задание так, чтобы его результат постепенно сохранялся в БД (допустим помечать обработанные ноды, чтобы ни не попали в следущее задание). Тогда можно будет когда нужно прервать задание, а потом безболезненно и без потери результатов запустить его заново.
Спасибо, но интересует именно теоретическая основа данной технологии. Т.е. как, например, применить ее к процессу упаковки большого числа файлов? Добавлять по одному? А если попадется 1 большой файл, который не удастся запаковать в один присест?
В том то и суть, что если попадается задача, которую нельзя разбить на этапы, подход более чем бесполезен.
Конкретно про упаковку файлов могу сказать, что в данном случае чаще всего просто пишется специальная програмка упаковщик. Задание для нее можете заносить в БД через сайт, а програмка сама оттуда будет его получать.
Например подобный подход используется на Drupal.org для создания релизов модулей. С некоторой частотой (для дев релизов 2 раза в день, для стабильных релизов раз в 5 минут) программа паковщик проходится по git репозиториям модулей и создает скачиваемый архив.
Sign up to leave a comment.

Articles