Концепция довольно проста.
Когда вы устонавливаете задание для батч, задание помещается в БД.
Затем происходит переход на страницу с JavaScript кодом который начинает делать последовательные асинхронные запросы на сервер (в друпал к странице example.com/batch) передавая в качестве одного из параметров ID задания.
Сервер выполняет часть этого задания (одну операцию или одну одну итерацию) и возвращает назад либо сообщение о том что перация выполнена либо процент выполнения.
Таким образом вся магия заключается в том, что большое задание разбивается на несколько этапов и соотвествено несколько запросов, позволяя избежать при этом превышения максимального времени выполнения скрипта.
Минус всего этого заключается в том, что при закрытии страничке в браузере с выполняющимся заданием работа механизма прекращается т.к. некому становиться посылать запросы на сервер. Этот эффект можно немного смягчить, если спланировать задание так, чтобы его результат постепенно сохранялся в БД (допустим помечать обработанные ноды, чтобы ни не попали в следущее задание). Тогда можно будет когда нужно прервать задание, а потом безболезненно и без потери результатов запустить его заново.
Представьте что у Вас есть некоторый запрос $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'] не переходит между операциями.
Callback операции в качестве последнего аргумента должен принимать по ссылке переменную &$context.
В принципе нет нужды как у Вас через цикл создавать отдельную операцию для каждой ноды.
Корректнее будет передать в операцию весь массив а в конце выполнения операции устанавливать значение $context['finished'] равное количеству обработанных нод деленному на общую длину массива. Прогресс можно сохранять в массиве $context['sandbox']. Операция будет автоматически вызываться до тех пор пока $context['finished'] не примет в качестве значения единицу.
Такой подход лучше
1. С точки зрения идеологии и эстетики: т.к. в батче по хорошему должна быть 1 колбэк — 1 операция (За очень редким исключением. Допустим если надо выполнить операцию А потом Б а потом сново А например)
2. С точки зрения производительности. Батч сохраняет последовательность операций в БД. А теперь представьте что у Вас рабочая ситуация и ноды достаются из БД в количестве 100500+ штук. Вот у Вас и запишется в ячейку 100500+ операций. А на самом деле нужно записать только 1.
Вот собственно с апрельской конференции video.yandex.ru/users/vaspi/view/40
Доклад от ребят из Axel Springer (Forbes) по поводу настройки окружения для Drupal под high loaded проект.
Вот собственно с апрельской конференции video.yandex.ru/users/vaspi/view/40
Доклад от ребят из Axel Springer (Forbes) по поводу настройки окружения для Drupal под high loaded проект.
В 7 уже активно используется ООП. А полного перехода на объектную модель и отказа от системы хуков и конвенциональных функций вроде как пока и в 8ке не планируется. Строго говоря я еще не видел более или менее вменяемой аргументации в пользу того что такой переход вообще нужен.
Не люблю такие статье вида «я люблю то-то за то-то» или «я не люблю это за это» т.к. они вызывают классический (и чаще всего на 80% бессмысленный и бездоказательный" срач.
Наверное полезная статья для тех кто о Drupal вообще не слышал.
А кто тут возмущается насчет производительности, запутанности и т.п. проконсультируйтесь с ребятами из Axel Springer. Forbes.ru один из самых загруженных ресурсов России не считая соц сетей и успешно работает на друпале. При это работает это все не на огромном кластере а на 6 серверах (2бэ+2фэ+2бд) 3 из которых являются репцлицирующими.
Я прогонял. Только я прогонял из меню модулей а не из меню кодера. А оттуда оно по умолчанию прогоняется на нормале. На друпалорге попросили прогнать на миноре.
Во общем исправлять там не много, завтра к вечеру думаю все исправлю.
Поискал в запросах на функционал (feature requests): drupal.org/node/1004970
Там сказано что реализовывать данный функционал в рамках модуля References не планируется, но уже есть надстройки.
Тоже правда. На самом деле если рассматривать задачу в комплексе довольно интересно получается. Думал по этому поводу, есть такое неординарное решение.
Сделать тип поля которое бы было ссылкой на ноду.
Как будет работать:
Добавляете к материалу тип поля node_reference (назовем его так, кпримеру)
В настройках поля указываете на ноды какого типа будет ссылаться.
Также как и для любого поля можно указать чтобы количество элементов полей было N или неограничено.
Далее когда добавляете материал, можете сразу в процессе добавления этого материала, также как обычно заполняете поля, заполнить поле ассоциированных нод. После создания материала автоматически создаются эти ноды и связываются с ним. Потом также можно редактировать их либо по отдельности либо из родительского материала.
Когда вы устонавливаете задание для батч, задание помещается в БД.
Затем происходит переход на страницу с JavaScript кодом который начинает делать последовательные асинхронные запросы на сервер (в друпал к странице example.com/batch) передавая в качестве одного из параметров ID задания.
Сервер выполняет часть этого задания (одну операцию или одну одну итерацию) и возвращает назад либо сообщение о том что перация выполнена либо процент выполнения.
Таким образом вся магия заключается в том, что большое задание разбивается на несколько этапов и соотвествено несколько запросов, позволяя избежать при этом превышения максимального времени выполнения скрипта.
Минус всего этого заключается в том, что при закрытии страничке в браузере с выполняющимся заданием работа механизма прекращается т.к. некому становиться посылать запросы на сервер. Этот эффект можно немного смягчить, если спланировать задание так, чтобы его результат постепенно сохранялся в БД (допустим помечать обработанные ноды, чтобы ни не попали в следущее задание). Тогда можно будет когда нужно прервать задание, а потом безболезненно и без потери результатов запустить его заново.
В самой операции делаете свой запрос $sql с LIMIT $a,$a+$k где
$a — то сколько вы нод уже обработали (отступ)
$k — сколько нод вы хотите обрабатывать за одну итерацию (так чтобы итерация занимала приемлимое для Вас время, например 10 секунд)
Потом идет что-то типо такого блока
Таким образом операция будет выполняться пока $context['finished'] не станет 1 при этом сообщая батчу о прогрессе после каждой итерации. Обратите внимание на то, что $context['sandbox'] не переходит между операциями.
api.drupal.org/api/drupal/includes--form.inc/group/batch/6
В принципе нет нужды как у Вас через цикл создавать отдельную операцию для каждой ноды.
Корректнее будет передать в операцию весь массив а в конце выполнения операции устанавливать значение $context['finished'] равное количеству обработанных нод деленному на общую длину массива. Прогресс можно сохранять в массиве $context['sandbox']. Операция будет автоматически вызываться до тех пор пока $context['finished'] не примет в качестве значения единицу.
Такой подход лучше
1. С точки зрения идеологии и эстетики: т.к. в батче по хорошему должна быть 1 колбэк — 1 операция (За очень редким исключением. Допустим если надо выполнить операцию А потом Б а потом сново А например)
2. С точки зрения производительности. Батч сохраняет последовательность операций в БД. А теперь представьте что у Вас рабочая ситуация и ноды достаются из БД в количестве 100500+ штук. Вот у Вас и запишется в ячейку 100500+ операций. А на самом деле нужно записать только 1.
Доклад от ребят из Axel Springer (Forbes) по поводу настройки окружения для Drupal под high loaded проект.
Доклад от ребят из Axel Springer (Forbes) по поводу настройки окружения для Drupal под high loaded проект.
Во первых нравится, а во вторых если сравнивать разработку под 7ку и под 6ку видна явная динамика в сторону улучшения качества кода.
www.eve-pirate.com/uploads/LearningCurve.jpg
А кто тут возмущается насчет производительности, запутанности и т.п. проконсультируйтесь с ребятами из Axel Springer. Forbes.ru один из самых загруженных ресурсов России не считая соц сетей и успешно работает на друпале. При это работает это все не на огромном кластере а на 6 серверах (2бэ+2фэ+2бд) 3 из которых являются репцлицирующими.
Я прогонял. Только я прогонял из меню модулей а не из меню кодера. А оттуда оно по умолчанию прогоняется на нормале. На друпалорге попросили прогнать на миноре.
Во общем исправлять там не много, завтра к вечеру думаю все исправлю.
Там сказано что реализовывать данный функционал в рамках модуля References не планируется, но уже есть надстройки.
drupal.org/project/nodeconnect
вот вроде то что надо
Сделать тип поля которое бы было ссылкой на ноду.
Как будет работать:
Добавляете к материалу тип поля node_reference (назовем его так, кпримеру)
В настройках поля указываете на ноды какого типа будет ссылаться.
Также как и для любого поля можно указать чтобы количество элементов полей было N или неограничено.
Далее когда добавляете материал, можете сразу в процессе добавления этого материала, также как обычно заполняете поля, заполнить поле ассоциированных нод. После создания материала автоматически создаются эти ноды и связываются с ним. Потом также можно редактировать их либо по отдельности либо из родительского материала.
Вот такая идея. можно развить :)