爲了異步處理事件並創建活動源,我使用了Sidekiq和Ruby on Rails的全局ID。使用Sidekiq執行異步作業時處理過時的數據
這適用於大多數類型的活動,但其中一些需要的數據可能隨着作業執行時間而改變。
這裏是一個完全虛構的例子:
class Movie < ActiveRecord::Base
include Redis::Objects
value :score # stores an integer in Redis
has_many :likes
def popular?
likes.count > 1000
end
end
而一個Sidekiq工人每一個電影被更新時進行工作:
class MovieUpdatedWorker
include Sidekiq::Worker
def perform(global_id)
movie = GlobalID::Locator.locate(global_id)
MovieUpdatedActivity.create(movie: movie, score: movie.score) if movie.popular?
end
end
現在,想象Sidekiq相對滯後,在此之前它有機會執行它的工作,電影的score
在Redis中更新,一些用戶不喜歡該電影,並且popular
方法現在返回false。
Sidekiq最終使用更新的數據。
我正在尋找安排作業的方式,同時確保執行作業時所需的數據不會更改。有幾個想法:
1 /手動傳遞所需的所有數據,並相應地調整工人:
MovieUpdatedWorker.perform_async(
movie: self,
score: score,
likes_count: likes.count
)
這可以工作,但將需要重新實現/複製依賴於諸如score
和popular?
數據的所有方法(想象一個比這兩個/三個可移動部件多得多的應用程序)。
由於序列化對象在Redis中可能佔用很多空間,所以這並不能很好地擴展。
2 /存根上的工人通過記錄一些方法:
MovieUpdatedWorker.perform_async(
global_id,
stubs: { score: score, popular?: popular? }
)
class MovieUpdatedWorker
include Sidekiq::Worker
def perform(global_id, stubs: {})
movie = GlobalID::Locator.locate(global_id)
# inspired by RSpec
stubs.each do |message, return_value|
movie.stub(message) { return_value }
end
MovieUpdatedActivity.create(movie: movie, score: movie.score) if movie.popular?
end
end
這不是功能性的,但你能想象處理實際記錄的方便,不必重新實現現有方法,並處理實際的數據。
您是否看到過其他策略來「凍結」對象數據並對其進行異步處理?你怎麼看待這兩個?
你說得對,我修改了標題並改寫了問題。謝謝! –