Чтобы асинхронно обрабатывать события и создавать фид активности, я использую глобальный идентификатор Sidekiq и Ruby on Rails.Работа со устаревшими данными при выполнении асинхронных заданий с 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?
(представьте себе приложение с гораздо большим количеством этих двух/трех подвижных частей).
Это не очень хорошо масштабируется, поскольку сериализованные объекты могут занимать много места в Редисе.
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
Это не работает, но вы можете себе представить, удобство работы с фактической записью, не имея переопределять существующие методы , и обработки фактических данных.
Вы видите другие стратегии «заморозить» данные объекта и асинхронно обрабатывать их? Что вы думаете об этих двух?
Вы правы, я исправил заголовок и перефразировал вопрос. Благодаря! –