2014-09-11 17 views
28

Tôi tìm thấy điều này Schedule one-time jobs in Rails nhưng điều này chỉ hiển thị lịch trình một lần. Tôi quan tâm đến việc lập kế hoạch cho một công việc định kỳ.Làm cách nào để lên lịch các công việc định kỳ trong Công việc Hoạt động (Rails 4.2)?

Delayed_job có này

self.delay(:run_at => 1.minute.from_now) 

Làm thế nào để làm điều gì đó như thế trong Rails 4.2/Active Job?

+1

Ví dụ DelayedJob bạn đã đăng sẽ là công việc một lần trong tương lai chứ không phải là công việc lặp đi lặp lại, điều này sẽ chạy lặp đi lặp lại. Ý bạn là gì? – rossta

+0

Tôi muốn một lần chạy liên tục. –

+0

Tôi không tin rằng có một api ActiveJob cho điều đó. Tùy thuộc vào hệ thống nền của bạn, có các phần mở rộng (https://github.com/resque/resque-scheduler, https://github.com/ondrejbartas/sidekiq-cron) hoặc chỉ sử dụng cron (https://github.com)/tomykaira/clockwork, https://github.com/javan/whenever) – rossta

Trả lời

11

Bạn có thể chỉ cần tái enqueue công việc vào cuối thực hiện

class MyJob < ActiveJob::Base 
    RUN_EVERY = 1.hour 

    def perform 
    # do your thing 

    self.class.perform_later(wait: RUN_EVERY) 
    end 
end 
+8

Đó thực sự không phải là giải pháp đáng tin cậy: nếu ngoại lệ xảy ra, ngắt chuỗi và một số bộ điều hợp phụ trợ dường như không chấp nhận các đối số ActiveSupport :: Duration. Bạn cũng phải tự khởi chạy công việc lần đầu tiên. – Pak

+1

@Pak Bạn luôn thêm một khối 'đảm bảo' ở cấp phương thức hoặc trong một cuộc gọi lại' after_perform'. –

+0

Chúng tôi đã từng làm điều này, nó không đáng tin cậy vì một vài lý do. 1) nó không tính đến thời gian công việc của bạn mất. Nếu công việc của bạn mất 5 phút, đó là 2 giờ mỗi ngày, có nghĩa là bạn chạy khoảng 22 việc làm/24 giờ. (điều này có thể khắc phục được với đồng hồ toán học) 2) có khả năng một công việc không chạy do một công nhân đang xuống. Nếu bạn có một công việc mà nhìn vào "giờ gần đây nhất của x" khi nó chạy, nó sẽ không bao giờ bắt kịp. 3) khối đảm bảo không được đảm bảo để chạy trong trường hợp bị trả lại. nếu bạn đang chạy trên heroku, và làm một triển khai trong khi một công việc đang chạy, có một cơ hội tốt bạn giết quá trình. –

20

Nếu bạn muốn trì hoãn việc thực hiện công việc để 10 phút sau, hai lựa chọn:

  1. SomeJob.set(wait: 10.minutes).perform_later(record)

  2. SomeJob.new(record).enqueue(wait: 10.minutes)

Trì hoãn đến một thời điểm cụ thể từ bây giờ sử dụng wait_until.

  1. SomeJob.set(wait_until: Date.tomorrow.noon).perform_later(record)

  2. SomeJob.new(record).enqueue(wait_until: Date.tomorrow.noon)

Chi tiết vui lòng tham khảo http://api.rubyonrails.org/classes/ActiveJob/Base.html.

Đối với các công việc định kỳ, bạn chỉ cần đặt SomeJob.perform_now(record) trong cronjob (whenever).

Nếu bạn sử dụng Heroku, chỉ cần đặt SomeJob.perform_now(record) trong tác vụ cào theo lịch trình. Vui lòng đọc thêm về nhiệm vụ cào theo lịch trình tại đây: Heroku scheduler.

+2

Lưu ý rằng 'wait_until' mong đợi một thể hiện của' ActiveSupport :: TimeWithZone' trong khi 'wait' mong đợi một phiên bản' Date'. Thay vào đó, đối tượng được truyền tới 'wait_until' cần trả lời': to_f' và trả về "giây epoch" để đợi đến (giây kể từ ngày 1 tháng 1 năm 1970) – sameers

15

Tương tự như câu trả lời rab3 của, vì ActiveJob đã hỗ trợ cho callbacks, tôi đã nghĩ đến việc làm một cái gì đó giống như

class MyJob < ActiveJob::Base 
    after_perform do |job| 
    # invoke another job at your time of choice 
    self.class.set(:wait => 10.minutes).perform_later(job.arguments.first) 
    end 

    def perform(the_argument) 
    # do your thing 
    end 
end 

activejob callbacks

+0

Tôi thích điều này nhiều hơn một chút; cảm thấy có nhiều đường ray hơn. – deefour

2

Nếu bạn đang sử dụng resque như ActiveJob phụ trợ của bạn, bạn có thể sử dụng một kết hợp công việc Scheduling Jobs và active_scheduler của resque-scheduler (https://github.com/JustinAiken/active_scheduler, bao gồm các công việc theo lịch trình để hoạt động đúng với ActiveJob).

Các vấn đề liên quan