Рельсы периодическое задание
У меня есть приложение ruby on rails, в котором я пытаюсь найти способ запуска кода каждые несколько секунд.
Я нашел много информации и идей, используя cron или cron-подобные реализации, но они точны с точностью до минуты и / или требуют внешних инструментов. Я хочу запускать задачу каждые 15 секунд или около того, и я хочу, чтобы она была полностью автономной в приложении (если приложение останавливается, задачи останавливаются и не выполняются никакие внешние настройки).
Это используется для фоновой генерации данных кеша. Каждые несколько секунд задача собирает некоторые данные, а затем сохраняет их в кеше, который используется всеми клиентскими запросами. Задача довольно медленная, поэтому она должна выполняться в фоновом режиме, а не блокировать запросы клиентов.
Я довольно новичок в ruby, но у меня сильный опыт работы с perl, и я решил бы создать интервальный таймер и обработчик, который разветвляется, запускает код и затем завершает работу по завершении.
Возможно, было бы даже лучше просто смоделировать запрос клиента и получить сам контроллер rails. Таким образом, я мог начать задание, нажав на него URI (хотя, поскольку задание будет выполняться каждые несколько секунд, я сомневаюсь, что оно мне когда-нибудь понадобится, но, возможно, будет использоваться в будущем). Хотя было бы тривиально просто заставить контроллер вызывать любой метод, вызываемый планировщиком периодических задач (если он у меня есть).
7 ответов
Вообще говоря, я не знаю встроенного способа создания периодической задачи в приложении. Rails построен на Rack и ожидает получения http-запросов, что-то делает, а затем возвращает. Таким образом, вы просто должны управлять периодическим заданием самостоятельно.
Я думаю, учитывая частоту, с которой вам нужно запускать задачу, достойным решением может быть просто написать себе простое грабельное задание, которое повторяется вечно, и запустить его одновременно с запуском приложения, используя что-то вроде Foreman. Форман часто используется таким образом, чтобы управлять запуском / закрытием фоновых рабочих вместе с их приложениями. На производстве вы можете использовать что-то еще для управления процессами, например, Monit.
Я бы посоветовал когда-нибудь драгоценный камень https://github.com/javan/whenever
Это позволяет вам указать расписание, как:
every 15.minutes do
MyClass.do_stuff
end
Там нет планирования рабочих мест cron или манипулирования с внешними службами.
Вы можете написать свой собственный метод, что-то вроде
class MyWorker def self.work #do you work sleep 15 end end
запустить его с rails runner MyWorker.work
Там будет отдельный процесс, работающий в фоновом режиме
Или вы можете использовать что-то вроде Resque, но это другой подход. Это работает так: что-то добавляет задачу в очередь, в то время как работник выбирает любую работу в очереди и пытается ее завершить.
Так что это зависит от ваших собственных потребностей.
Я знаю, что это старый вопрос. Но, возможно, для кого-то этот ответ может быть полезным. Существует драгоценный камень под названием Crono.
Crono - это демон планировщика фоновых заданий, основанный на времени (как и Cron) для Ruby on Rails.
Кроно - это чистый Рубин. Он не использует Unix Cron и другие вещи, зависящие от платформы. Таким образом, вы можете использовать его на всех платформах, поддерживаемых Ruby. Он сохраняет рабочие состояния в вашей базе данных, используя Active Record. Вы имеете полный контроль над процессом выполнения работ. Это Ruby, так что вы можете понять и изменить его в соответствии со своими потребностями.
Удивительная вещь с Crono заключается в том, что его код объясняется самостоятельно. Чтобы периодически выполнять задачу, вы можете просто:
Crono.perform(YourJob).every 2.days
Может быть, вы также можете сделать:
Crono.perform(YourJob).every 30.seconds
Во всяком случае, вы действительно можете сделать много вещей. Другой пример может быть:
Crono.perform(TestJob).every 1.week, on: :monday, at: "15:30"
Я предлагаю этот драгоценный камень вместо того, чтобы когда-либо, потому что всякий раз, когда используется таблица Unix Cron, которая не всегда доступна.
Отбрасывание решения только потому, что оно выглядит несколько элегантно и отвечает на вопрос без каких-либо дополнительных жемчужин. В моем сценарии я хотел запустить некоторый код, но только после того, как все мои рабочие Sidekiq сделали свою работу.
Сначала я определил метод, чтобы проверить, работают ли какие-либо рабочие...
def workers_working?
workers = Sidekiq::Workers.new.map do |_process_id, _thread_id, work|
work
end
workers.size > 0
end
Затем мы просто вызываем метод с циклом, который спит между вызовами.
sleep 5 while workers_working?
Используйте тонкий или другой сервер, который использует eventmachine, а затем просто используйте таймеры, которые являются частью eventmachine. Пример: в config/application.rb
EM.add_periodic_timer(2) do
do_this_every_2_sec
end
Использовать что-то вроде отложенной работы и требовать его так часто?