Как я могу начать повторять фоновые задания, когда пользователь посещает веб-страницу?

Я работаю над созданием веб-приложения Rails с фоновыми рабочими для выполнения некоторых задач в фоновом режиме с заданным интервалом. Я использую Resque с Redis для постановки в очередь фоновых заданий и использую Resque-планировщик, чтобы запускать его с заданным интервалом, например, каждые 30 секунд или около того.

Фоновое задание необходимо ставить в очередь только тогда, когда пользователь посещает определенную страницу, и оно должно выполняться по расписанию, пока пользователь не уйдет с этой страницы. В принципе, я хотел бы установить расписание динамически во время выполнения. My application is deployed in Cloud, and the main Rails app and the background workers run as a separate processes communicating through Redis. How can I set the schedule dynamically, and from where?

resque_schedule.yml

do_my_job:
  every: 1m
  class: BackgroundJob
  description: Runs the perform method in MyJob
  queue: backgroundq

inside the controller

  def index
    Resque.enqueue(BackgroundJob)
  end

background_job.rb

class BackgroundJob
  @queue = :backgroundq

  @job_helper = BackgroundHelper.new

  def self.perform
    @job_helper.get_job_data
  end

end

1 ответ

Resque-scheduler может делать то, что вы описываете, используя динамические графики. Каждый раз, когда пользователь посещает вашу страницу, вы создаете расписание с Resque.set_schedule который запускается каждые 30 секунд для этого пользователя. Когда пользователь уходит, вы прерываете Resque.remove_schedule, Я могу представить себе множество способов, которыми пользователь мог бы покинуть страницу, не обращая на вас внимания (наихудший случай, что, если его компьютер потерял питание?), Поэтому я буду беспокоиться о том, что расписание останется. Я также не уверен, насколько счастливым остается resque-scheduler, когда вы добавляете все больше и больше расписаний, поэтому у вас могут возникнуть проблемы с большим количеством пользователей.


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

class BackgroundJob
  def self.perform
    User.active.each { ... }
  end
end

Если вы делаете что-то вроде набора User#last_seen_at когда пользователь заходит на вашу страницу и имеет User.active загрузите всех, кого видели за последние 10 минут, затем вы будете запускать каждые 30 секунд для всех своих активных пользователей, и не будет никаких шансов на то, что задания пользователя продолжатся хорошо после того, как они уйдут, потому что время ожидания истекает через 10 минут. Однако, если у вас больше пользователей, чем вы можете выполнить за 30 секунд, запланированное задание не будет завершено до запуска следующей копии, и возникнут проблемы. Возможно, вам удастся обойти это, поставив задачу верхнего уровня для каждого пользователя в очередь на дополнительную работу, которая фактически выполняет эту работу. Тогда до тех пор, пока вы можете сделать это за 30 секунд и иметь достаточное количество работников для выполнения своей работы, все должно быть хорошо.


Третий способ подойти к этому - поручить заданию пользователя поставить в очередь другую копию, например:

class BackgroundJob
  def self.perform(user_id)
    do_work(user_id)
    Resque.enqueue_in(30.seconds, BackgroundJob, user_id)
  end
end

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


Наконец, я бы спросил, является ли Resque подходящим инструментом для вашей задачи. Если вы хотите, чтобы что-то происходило каждые 30 секунд, пока пользователь находится на странице, вероятно, вы хотите, чтобы пользователь видел, что это происходит, поэтому вам следует рассмотреть возможность его реализации в браузере. Например, вы можете установить 30-секундный интервал JavaScript для достижения конечной точки API, которая выполняет некоторую работу и возвращает значение. Это вообще исключает необходимость в Resque и автоматически останавливается, когда пользователь уходит, даже если он теряет энергию и ваш код не получает возможности для очистки.

Другие вопросы по тегам