2012-10-07 49 views
6

Tôi đang viết một tác vụ cào sẽ được gọi mỗi phút (có thể sau mỗi 30 giây trong tương lai) bởi Bất cứ khi nào, và nó liên lạc điểm đầu cuối API (mỗi người dùng trong cơ sở dữ liệu của chúng tôi). Rõ ràng, điều này là không hiệu quả chạy như một chủ đề duy nhất, nhưng nó có thể đa luồng? Nếu không, có một thư viện HTTP dựa trên sự kiện tốt sẽ có thể hoàn thành công việc không?Nhiệm vụ cào đa luồng

Trả lời

12

Tôi đang viết một nhiệm vụ cào mà có thể gọi mỗi phút (có thể mỗi 30 giây trong tương lai) bằng cách Bất cứ khi nào

Cẩn thận với Rails thời gian khởi động, nó có thể là tốt hơn để sử dụng một forking mô hình như Resque hoặc Sidekiq, Rescue cung cấp https://github.com/bvandenbos/resque-scheduler mà sẽ có thể làm những gì bạn cần, tôi không thể nói về Sidekiq, nhưng tôi chắc chắn rằng nó có một cái gì đó tương tự có sẵn (Sidekiq là mới hơn Resque)

Rõ ràng, điều này không hiệu quả chạy như một sợi đơn , nhưng có thể đa luồng không? Nếu không, có một thư viện HTTP dựa trên sự kiện tốt sẽ có thể hoàn thành công việc không?

tôi muốn đề nghị bạn nhìn vào ActiveRecord's find_each cho mẹo để làm cho quá trình tìm bạn hiệu quả hơn, một khi bạn có lô của bạn, bạn có thể dễ dàng làm điều gì đó sử dụng chủ đề như:

# 
# Find each returns 50 by default, you can pass options 
# to optimize that for larger (or smaller) batch sizes 
# depending on your available RAM 
# 
Users.find_each do |batch_of_users| 
    # 
    # Find each returns an Enumerable collection of users 
    # in that batch, they'll be always smaller than or 
    # equal to the batch size chosen in `find_each` 
    # 
    # 
    # We collect a bunch of new threads, one for each 
    # user, eac 
    # 
    batch_threads = batch_of_users.collect do |user| 
    # 
    # We pass the user to the thread, this is good 
    # habit for shared variables, in this case 
    # it doesn't make much difference 
    # 
    Thread.new(user) do |u| 
     # 
     # Do the API call here use `u` (not `user`) 
     # to access the user instance 
     # 
     # We shouldn't need to use an evented HTTP library 
     # Ruby threads will pass control when the IO happens 
     # control will return to the thread sometime when 
     # the scheduler decides, but 99% of the time 
     # HTTP and network IO are the best thread optimized 
     # thing you can do in Ruby. 
     # 
    end 
    end 
    # 
    # Joining threads means waiting for them to finish 
    # before moving onto the next batch. 
    # 
    batch_threads.map(&:join) 
end 

này sẽ bắt đầu có nhiều hơn batch_size chuỗi, chờ sau mỗi batch_size để hoàn tất. Bạn có thể làm điều gì đó như thế này, nhưng sau đó bạn sẽ có một số chủ đề không kiểm soát được, có một giải pháp thay thế bạn có thể hưởng lợi từ đây, nó phức tạp hơn bao gồm cả ThreadPool và danh sách công việc được chia sẻ làm, tôi đã đăng nó như tại Github so'as không spam stackoverflow: https://gist.github.com/6767fbad1f0a66fa90ac

+0

ThreadPool trông tuyệt vời! Tôi sẽ thử nó ra –

+0

Thứ tốt, cảm ơn :) – Robin

3

Tôi khuyên bạn nên sử dụng sidekiq tuyệt vời khi đa luồng. Sau đó, bạn có thể enqueue công việc riêng biệt cho mỗi người dùng để bỏ phiếu cho API. clockwork có thể được sử dụng để thực hiện các công việc bạn enqueue định kỳ.

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