2012-04-07 9 views
5

Ứng dụng của tôi tạo các công việc resque phải được xử lý tuần tự cho mỗi người dùng và chúng sẽ được xử lý nhanh nhất có thể (trễ tối đa 1 giây).Resque: các công việc thời gian quan trọng được thực thi tuần tự cho mỗi người dùng

Ví dụ: job1 và job2 được tạo cho user1 und job3 cho user2. Resque có thể xử lý song song job1 và job3, nhưng job1 và job2 cần được xử lý tuần tự.

tôi có những suy nghĩ khác nhau cho một giải pháp:

  • tôi có thể sử dụng hàng đợi khác nhau (ví dụ queue_1 ... queue_10) và bắt đầu một công nhân cho mỗi hàng đợi (ví dụ rake resque:work QUEUE=queue_1). Người dùng được chỉ định vào hàng đợi/công nhân khi đang chạy (ví dụ: khi đăng nhập, mỗi ngày, v.v.)
  • Tôi có thể sử dụng "hàng đợi người dùng" động (ví dụ: hàng đợi _ # {user.id}) và cố gắng mở rộng lại chỉ 1 công nhân có thể xử lý hàng đợi tại một thời điểm (như được yêu cầu trong Resque: one worker per queue)
  • Tôi có thể đặt công việc vào hàng đợi không được phục hồi và sử dụng "công việc meta cho mỗi người dùng" bằng cách khóa lại (https://github.com/defunkt/resque-lock).

Bạn có kinh nghiệm nào với một trong những tình huống đó trong thực tế không? Hay có những ý tưởng khác có thể đáng để suy nghĩ? Tôi sẽ đánh giá cao bất kỳ đầu vào, cảm ơn bạn!

Trả lời

5

Nhờ câu trả lời của @Isotope cuối cùng tôi đã đến một giải pháp mà dường như làm việc (sử dụng resque-retry và khóa trong redis:

class MyJob 
    extend Resque::Plugins::Retry 

    # directly enqueue job when lock occurred 
    @retry_delay = 0 
    # we don't need the limit because sometimes the lock should be cleared 
    @retry_limit = 10000 
    # just catch lock timeouts 
    @retry_exceptions = [Redis::Lock::LockTimeout] 

    def self.perform(user_id, ...) 
    # Lock the job for given user. 
    # If there is already another job for the user in progress, 
    # Redis::Lock::LockTimeout is raised and the job is requeued. 
    Redis::Lock.new("my_job.user##{user_id}", 
     :expiration => 1, 
     # We don't want to wait for the lock, just requeue the job as fast as possible 
     :timeout => 0.1 
    ).lock do 
     # do your stuff here ... 
    end 
    end 
end 

Tôi đang sử dụng ở đây Redis :: Khóa từ https://github.com/nateware/redis-objects (nó đóng gói mẫu từ http://redis.io/commands/setex)

2

Tôi đã làm điều này trước đây.

Giải pháp tốt nhất để đảm bảo tuần tự cho những thứ như thế này là để kết thúc công việc1 xếp hàng công việc2. job1's và job2's sau đó có thể đi cùng hàng đợi hoặc hàng đợi khác nhau, nó sẽ không quan trọng đối với tuần tự, tùy thuộc vào bạn.

Bất kỳ giải pháp nào khác, chẳng hạn như xếp hàng công việc1 + 2 cùng một lúc NHƯNG yêu cầu job2 bắt đầu trong 0,5 giây sẽ dẫn đến điều kiện chủng tộc, vì vậy điều đó không được khuyến nghị.

Có job1 trigger job2 cũng rất dễ thực hiện.

Nếu bạn muốn một tùy chọn khác vì lợi ích của nó: Đề xuất cuối cùng của tôi sẽ là gộp cả hai công việc thành một công việc và thêm một tham số nếu phần thứ hai cũng được kích hoạt.

ví dụ:

def my_job(id, etc, etc, do_job_two = false) 
    ...job_1 stuff... 
    if do_job_two 
    ...job_2 stuff... 
    end 
end 
+0

Vấn đề là job1 không nên biết rõ về job2 vì chúng không được tạo cùng một lúc (chúng có thể được tạo trong các yêu cầu khác nhau, v.v.) – lacco

+0

Trong trường hợp này tôi muốn sử dụng thử lại lần nữa, trên job2, để thực hiện một kiểm tra nếu job1 được hoàn thành và nếu không được xếp lại sau đó - thử lại, có thể được thiết lập để sử dụng hoặc là backoffs mũ hoặc giới hạn trys khi cần thiết. – TomDunning

+0

Cách job2 biết rằng công việc 1 đang được tiến hành cho một người dùng cụ thể? – lacco