Cron Splitter - модуль для разбиения работы крона на части.

Аватар пользователя EliteMonk EliteMonk 16 марта 2010 в 18:27

Не смог найти нужного модуля, поэтому попытался написать сам, выкладываю что получилось, если кто знает модуль реализующий нужную мне возможность (описание ниже) отпишитесь, не хочу изобретать велосипед. С радостью выложил бы на drupal.org но не знаю как, поделитесь как это сделать.

Описание:
Модуль лишь помощник для других модулей. Столкнулся с такой проблемой, на сайте который будет вести различную статистику, необходим постоянный перерасчёт, и реализован пока 1 модуль, но скоро их будет несколько. Нужно не только разбить выполнение одного модуля на части но и сделать выполнение модулей поочерёдно. Для примера задача перерасчёта для одного модуля целиком выполняется 2 дня. Но можно разбить на логические части выполнение каждой по 5 мин, что приемлемо с расчётом запуска крона каждые 10 мин. Но если модулей будет 10 и каждый будет иметь работу на 5 мин, а при добавлении 11-го модуля заново в ручную выставлять время для каждого модуля модуля чтобы не пересекались просто кошмарно =)

Коротко:
Модуль запоминает который модуль работал в последний раз и при следующем вызове крона отдаёт право работы следующему по списку модулю. При этом для каждого модуля имеет индекс задачи и подзадачи, их естественно тоже запоминает и когда очередь вновь дойдёт до этого модуля он вызовется со следующими по списку индексами.

Использование:
В своём модуле нужно реализовать 3 хука.

1. хук должен вернуть кол-во задач нужных этому модулю. Например если задач 4 то просто

function hook_cron_splitter_parts() {
  return 4;
}

2. хук должен вернуть кол-во подзадач нужных этому модулю для конкретной задачи. Например если подзадач 40*20=800 для задачи 3 а для остальных по одной, то функция будет выглядеть так:

function hook_cron_splitter_subparts($index) {
  switch ($index) {
    case 3:
      return 40*20;
    default:
      return 1;
  }
}

3. хук должен описывать саами задачи, т.е. замена стандартного hook_cron()

function hook_cron_splitter_tick($index, $subIndex) {
  switch ($index) {
    case 0:
      // Здесь задача 1
      break;
    case 1:
      // Здесь задача 2
      break;
    case 2:
      // Здесь задача 3
      break;
    case 3:
      // Здесь задача 4 которая состаит из подзадач которая тоже состоит из подзадач
      // Да такая мега затратная задача мне попалась, которую копипайстить неохота, т.к. не китаец =)) а разбить на части надо
      $currentSubTask = (int)($subIndex / 20);
      $currentSubSubTask = $subIndex % 20;
      // далее логика...
      break;
  }
}

Сам модуль:

ВложениеРазмер
Иконка пакета cron_splitter.zip1.83 КБ
0 Thanks

Комментарии

Аватар пользователя orangeudav orangeudav 16 марта 2010 в 19:40

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

Аватар пользователя EliteMonk EliteMonk 16 марта 2010 в 19:44
"RxB" wrote:

http://drupal.org/project/supercron
Не?

Как я понимаю модули подобные этому только позволяют разбивать работу по модулям (и то вручную только, если я правильно понял), а в примере я привел когда нужно выполнение одного модуля разбить на 803 задачи, конечно сам модуль может запоминать какую подзадачу выполнял прошлый раз, но думаю это накладно, постоянно один и тот же функционал копипайстить из одного модуля в другой. В добавок, если не настраивать модули то крон завалиться, а так все модули которым необходим этот функционал будут записывать в зависимости, и уже при разработке модулей можно рассчитывать на выделенное время определённой длины...

Аватар пользователя EliteMonk EliteMonk 16 марта 2010 в 20:20
Geldora wrote:

elysiacron?

Он позволяет создавать задачи (я так понял что понятия подзадачи нет), но немного непонятно, можно задавать время запуска каждой из задачи, но мне нужно выполнение не более одного задания для всех модулей работающих через этот модуль разбиения работы крона, т.е. опять ручной расчёт времени запуска, а хочется чтобы о времени и о задаче и о подзадаче пёкся сам модуль, может я не умею пользоваться данным модулем, может уже кто-то решал с помощью этого модуля схожую задачу, поделитесь опытом...

Аватар пользователя riyuzakki riyuzakki 16 марта 2010 в 20:41

ИМХО
Объедини hook_cron_splitter_parts и hook_cron_splitter_subparts в один хук. Пусть он возвращает массив типа

<?php
$tasks
[] = array(
  
'#id' => 1,
);
$tasks[] = array(
  
'#id' => 'second',
);
$tasks[] = array(
  
'#id' => 'blah',
  
'#callback' => 'module_blah_task',
  
'#file' => 'module_tasks.inc',
);
?>

В первых двух случаях вызывается дефолтный колбэк hook_cron_splitter_task($task), например. В третьем инклудится файл module_tasks.inc и вызывается module_blah_task($task). В качестве параметра $task, кусок массива $tasks, соответствующий текущей задаче. Можно в массиве $tasks придумать еще параметры, например #name и #description, чтоб потом еще и администрилку для гибкой настройки прикрутить.
Про подзадачи не понял, зачем они нужны.
Так модуль лучше впишется в друпал.

Аватар пользователя EliteMonk EliteMonk 16 марта 2010 в 21:18

To riyuzakki
Сейчас поразбираюсь с тем что вы посоветовали, я уже думал об объединении, так же ещё до сих пор думаю о системе с неограниченным уровнем подзадач =))

подзадачи нужны в моём примере для тройного фора, т.е

<?php
for (...)
  for (...)
    for (...)
?>

чтобы не копировать логику я могу разбить запоминая на каком элементе какого фора я остановился в прошлый раз

и ещё смысл был такой что при отладке да и потом при сопровождении индекс задачи соответствует записи в таблице определённой, каждая запись это 1 элемент статистических данных, чтобы я всегда мог легко определить проблемное место, тоже относиться и к фор'ам, только для него используется индекс подзадачи, сейчас двумя индексами я определяю 3 точки, по идее уже сейчас понимаю что могут случиться ситуации когда нужно более двух индексов, пока самое первое что приходит на ум это естественно массивы.

Просто пока у меня не очень большой опыт написания открытых модулей под друпал, а закрытые они многое стерпят =))

Аватар пользователя EliteMonk EliteMonk 16 марта 2010 в 22:48

To fasdalf@fasdalf.ru
Спасибо огромное, похоже этот модуль сможет удовлетворить мои потребности, попробую поиграть с этим модулем завтра отпишусь тогда...

Аватар пользователя orangeudav orangeudav 16 марта 2010 в 22:56
"EliteMonk" wrote:

для тройного фора

Если логика усложняется всякими вложенными циклами, которое нужно прерывать и восстанавливать то можно перейти к архитектуре queue-worker.
То есть один раз генерируется очередь мелких работ, а потом обработчики (которых может быть и несколько) идут по ней уже независимо от чего либо.

Аватар пользователя fasdalf@fasdalf.ru fasdalf@fasdalf.ru 17 марта 2010 в 10:25

Я бы попробовал, но документации по нему - только исходник. К тому же надпись "beta" настораживает.

Аватар пользователя fasdalf@fasdalf.ru fasdalf@fasdalf.ru 17 марта 2010 в 11:22

Поковырял исходник drupal_queue. ИМХО чересчур усложнено. Так что наш выбор - job queue
Как минимум до тех пор, пока не будет хотя бы тройки примеров использования.

Аватар пользователя EliteMonk EliteMonk 18 марта 2010 в 1:17

Сегодня завершил анализ модуля Job queue, в принципе пока самый близкий по необходимой задачи, но нереально использовать в том виде который сейчас, в модуле есть понятие задачи, но любая задача в модуле это задача на одноразовое выполнение, так что придётся каждый раз вбивать все 803 задачи, т.е. в предложенном мною варианте всего 4 записи в таблице а в этом модуле 803. теперь САМОЕ ВАЖНОЕ выполнение идет по записям т.е. если первый модуль вбил 803 задачи то до второго модуля дело дойдёт только через 4 дня, хотя выделение времени должно происходить попеременно для разных модулей, чтобы если один модуль тормозной то пускай себе тормозит, но это не должно влиять на другие модули более быстрые в обработке... т.е. запоздание свежих статистических данных для большого модуля объяснить заказчику можно, а объяснить почему модуль с данными из 1000 строк опаздывает с обновлениями на неделю другую крайне сложно.

Завтра буду также пристально изучать drupal queue, тогда тоже отпишусь, и если оно того стоит выложу пример использования для будущих поколений ;)

Аватар пользователя fasdalf@fasdalf.ru fasdalf@fasdalf.ru 19 марта 2010 в 10:32
"EliteMonk" wrote:

САМОЕ ВАЖНОЕ выполнение идет по записям т.е. если первый модуль вбил 803 задачи то до второго модуля дело дойдёт только через 4 дня,

Для этого в job_queue есть приоритеты - можно выполнять длительные задачи только когда все короткие уже выполнены.

Аватар пользователя EliteMonk EliteMonk 19 марта 2010 в 16:40
<a href="mailto:fasdalf@fasdalf.ru">fasdalf@fasdalf.ru</a> wrote:
"EliteMonk" wrote:

САМОЕ ВАЖНОЕ выполнение идет по записям т.е. если первый модуль вбил 803 задачи то до второго модуля дело дойдёт только через 4 дня,

Для этого в job_queue есть приоритеты - можно выполнять длительные задачи только когда все короткие уже выполнены.

Это не решает проблемы, т.к. низко приоритетные задачи никогда не выполняться как я понял или когда начнут выполняться то прерывания не будет и всё равно на двое суток другие не получат времени, т.е. в любом случае это не решение. В общем этот модуль хороший но требует серьёзной доработки.

P.S. модуль хорош когда задачи ставятся большого объёма но редко, с предположением что иногда будут моменты когда все задачи выполнены и список задач пуст, сейчас же задача состоит в том чтобы управлять задачами которые будут всегда в большом количестве, большем чем может позволить машина и список задач будет постоянно большим и никогда не будет достигать нуля...