База данных поддерживает рабочую очередь - PullRequest
1 голос
/ 09 апреля 2011

Моя ситуация ...

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

Пример. Допустим, у меня есть работник, который ходит в магазин и покупает мне молоко раз в неделю.Я хотел бы сохранить эту работу и ее конфигурацию в таблице MySQL.Но, похоже, действительно плохая идея опрашивать таблицу (каждую секунду?) И видеть, какие задания готовы для помещения в конвейер выполнения.

Все мои работники написаныв javascript, поэтому я использую node.js для выполнения и beanstalkd в качестве конвейера.

Если создаются новые задания (т. е. планирование работника для запуска в данное время)асинхронно, и мне нужно постоянно сохранять результат работы и конфигурацию, как мне избежать опроса таблицы?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 09 апреля 2011

Я согласен, что это кажется не элегантным, но, учитывая работу компьютеров что-то * где-то *, придется провести опрос какой-то , чтобы выяснить, какие заданиявыполнить когда.Итак, давайте рассмотрим некоторые из ваших вариантов:

  1. Опрос таблицы базы данных.Это совсем не плохая идея - это, вероятно, самый простой вариант, если вы все равно храните задания в MySQL.Частота одного запроса в секунду - ничто. Попробуйте, и вы заметите, что ваша система даже не чувствует этого.

    Некоторые идеи, которые помогут вам масштабировать это до, возможно, сотен запросов в секунду или просто сократить требования к системным ресурсам:

    • Создайте вторую таблицу 'job_pending', куда вы помещаетезадания, которые должны быть выполнены в течение следующих X секунд / минут / часов.
    • Запускайте запросы к вашей большой таблице всех заданий только один раз в течение долгого времени, а затем заполняйте небольшую таблицу, к которой вы обращаетесь каждый раз.
    • Удалите задания, которые были выполнены из небольшого стола, чтобы он был маленьким.
    • Используйте индекс для вашего столбца execute_time (или как вы его называете).
  2. Если вам нужно масштабировать еще больше, сохраните основную таблицу заданий в базе данных и используйте вторую, меньшую таблицу, которую я предлагаю, просто поместите эту таблицу в ОЗУ: либов виде таблицы памяти в движке БД или в какой-то очереди в вашей программе.Запрашивайте очередь с очень короткими интервалами, если у вас есть - потребуются некоторые крайние случаи использования, чтобы вызвать какие-либо проблемы с производительностью.

    Основная проблема с этим параметром заключается в том, что вам придется отслеживать заданиякоторые были в памяти, но не выполнялись, например, из-за сбоя системы - больше кода для вас ...

  3. Создать поток для каждого из множества заданий (скажем, всезаданий, которые должны быть выполнены в следующую минуту), и вызовите thread.sleep (millis_until_execution_time) (или что-то еще, я не очень знаком с node.js).

    Эта опция имеет ту же проблему, что и no.2 - где вы должны следить за выполнением задания для восстановления после сбоя.Это также самое расточительное imo - каждый спящий поток работы по-прежнему занимает системные ресурсы.

Конечно, могут быть дополнительные опции - я надеюсь, что другие ответят с большим количеством идей.

Просто поймите, что опрос БД каждую секунду вовсе не плохая идея.Это самый простой способ imo (помните KISS), и в этом случае у вас не должно быть проблем с производительностью, поэтому избегайте преждевременной оптимизации.

1 голос
/ 11 апреля 2011

Почему бы не сохранить объект Job в файле node.js, сохраненный в базе данных.

var Job = {
   id: long,
   task: String,
   configuration: JSON,
   dueDate: Date,
   finished: bit
};

Я бы посоветовал вам сохранить идентификатор только в ОЗУ и оставить все остальные данные Job в базе данных.Когда ваша функция тайм-аута наконец-то запускается, ей нужно знать .id, чтобы получить другие данные.

var job = createJob(...); // create from async data somewhere.
job.save(); // save the job.
var id = job.id // only store the id in RAM
// ask the job to be run in the future.
setTimeout(Date.now - job.dueDate, function() {
    // load the job when you want to run it
    db.load(id, function(job) {
        // run it.
        run(job);
        // mark as finished
        job.finished = true;
        // save your finished = true state
        job.save();
    });
});
// remove job from RAM now.
job = null;

Если сервер когда-либо дает сбой, все, что вам нужно, это запросить все задания, которые имеют [finished=false], загрузитьих в оперативную память и снова запустите setTimeouts.

Если что-то пойдет не так, вы сможете перезагрузить компьютер так:

db.find("job", { finished: false }, function(jobs) {
    each(jobs, function(job) {
         var id = job.id;
         setTimeout(Date.now - job.dueDate, function() {
             // load the job when you want to run it
             db.load(id, function(job) {
                 // run it.
                 run(job);
                 // mark as finished
                 job.finished = true;
                 // save your finished = true state
                 job.save();
             });
         });
         job = null;
    });
});
...