ruby-on-rails - 这是 Rails 验证线程安全的吗

标签 ruby-on-rails multithreading activerecord sidekiq activemodel

这同时在多个 Sidekiq 实例和 worker 中运行,这似乎产生了一些问题,例如实例被分配了“最近被警告”的错误,而在不应该和相反的情况下。

这种情况很少见,但正在发生,这是问题所在还是其他原因?

class BrokenModel < ActiveRecord::Base
  validates_with BrokenValidator

end

class BrokenValidator < ActiveModel::Validator
  def validate record
    @record = record

    check_alerted
  end

  private

  def check_alerted
    if AtomicGlobalAlerted.new(@record).valid?
      @record.errors[:base] << "It was alerted recently"
    end

    p "check_alerted: #{@record.errors[:base]}"
  end
end

class AtomicGlobalAlerted
  include Redis::Objects
  attr_accessor :id

  def initialize id
    @id = id
    @fredis = nil

    Sidekiq.redis do |redis|
        @fredis = FreshRedis.new(redis, freshness: 7.days, granularity: 4.hours)
    end
  end

  def valid?
    @fredis.smembers.includes?(@id)
  end
end

最佳答案

我们在工作中遇到了类似的事情,经过大量挖掘终于弄清楚发生了什么。

类方法 validates_with 使用验证器的一个实例 (BrokenValidator) 来验证您尝试验证的类的所有实例 (BrokenModel)。通常这很好,但是您正在分配一个变量 (@record) 并在另一个方法 (check_alerted) 中访问该变量,因此其他线程正在分配 @record 而其他线程仍在尝试 check_alerted

有两种方法可以解决这个问题:

1) 将record传递给check_alerted:

class BrokenValidator < ActiveModel::Validator
  def validate(record)    
    check_alerted(record)
  end

  private

  def check_alerted(record)
    if AtomicGlobalAlerted.new(record).valid?
      record.errors[:base] << "It was alerted recently"
    end

    p "check_alerted: #{record.errors[:base]}"
  end
end

2) 使用 validates_with 的实例版本,它为您要验证的每个模型实例创建一个新的验证器实例:

class BrokenModel < ActiveRecord::Base
  validate :instance_validators

  def instance_validators
    validates_with BrokenValidator
  end

end

这两种解决方案都可以解决并发问题。如果您遇到任何其他问题,请告诉我。

关于ruby-on-rails - 这是 Rails 验证线程安全的吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36923269/

相关文章:

ruby-on-rails - rake db:migrate无法正常工作

ruby-on-rails - Rails 开发效率 - 顶级 Textmate 快捷方式

java - 为什么DCL使用 volatile ,而不使用final?我代码运行同样的效果

ruby-on-rails - 无法在 Rails 3.2.3 中批量分配 protected 属性

ruby-on-rails - Facebook Graph API 换行

java - 在 Elasticsearch 中加载自定义同义词文件时出错

android - CalledFromWrongThreadException 使用基于 PhoneGap 的 Activity 修改 View

c++ - 静态数组访问冲突?

ruby-on-rails - 具有许多列的 ActiveRecord 表 : is there a better way?

ruby-on-rails - Rails 嵌套属性 : require at least two records