Carrierwave 是线程安全的吗?

Is Carrierwave thread-safe?

我正在使用 Sidekiq 和 Carrierwave 将图像上传到 S3。后台作业执行以下操作:

  1. 从远程下载图像url;
  2. 使用 minimagick 调整大小;
  3. 将调整大小的图像上传到 S3。

这是代码片段:

  def store_for_mobile(file)
     self.class.process optimize: [1080, 810]
     %w(android ios).each do |device|
        @directory = File.join('banners/mobile', device)
        store!(file)
     end
  end

  def store_for_web(file)
     self.class.process optimize: [750, 562]
     @directory = 'stores/750x562/'
     store!(file)
  end

  def store_header(file)
    self.class.process resize_to_limit: [640, 640]
    @directory = 'headers/images/consumer_app_brand_logos/'
    store!(file)
  end

  def store_header_mailer(file)
    self.class.process resize_to_limit: [360, 120]
    @directory = 'headers/images/360x120/'
    store!(file)
  end

以上方法分别在不同的作业中执行,也就是说有时它们是运行并发的。

很快我注意到一些调整大小store_header_mailer的图片被上传到本应属于store_for_mobilestore_for_webstore_header的目录中。 (例如 'headers/images/consumer_app_brand_logos/' 得到 120x120 图片)

我在使用 Resque 时不存在这个问题。

我查看了 carrierwave 的源代码,发现

https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/uploader/processing.rb#L54

它在调用 image_magick 命令行时使用 class 变量 self.processors 和 class 方法 self.process

这部分代码是线程安全的吗?提前致谢。

花了几天时间搞清楚是怎么回事。这是一个有趣的案例,在这里解释它也太长了,所以我决定为它写一个post,所以更多细节请在那里阅读。


总而言之,carrierwave使用class变量来保存处理器方法和尺寸,上传完成后不会重置,因此会影响下一个上传者。