【问题标题】:Rails paperclip upload images folder - Errno::EMFILERails 回形针上传图片文件夹 - Errno::EMFILE
【发布时间】:2013-09-06 09:32:29
【问题描述】:

首先我想为我糟糕的英语道歉。

我有一段代码使用 gem PaperClip 3.3.1 上传到服务器文件夹的文件。 在我尝试上传包含 50 张照片的文件夹之前,每张照片(最多 30 张)看起来都很棒。然后我收到以下错误消息:

Errno::EMFILE (Too many open files - identify -format %m '/tmp/4209520130906-10816-1kk0w0o.jpg[0]'):

我在我的系统和环境中检查 ulimit -a 我可以同时打开 1200 个文件。 然后我运行了 commad:

watch -n1 'lsof -a -p <rails server pid> | wc -l'

并且随着每次迭代打开文件的数量在增加

110 - starting count
160 - after first iteration (number from folder)
240 - second iteration
320
376
457
...
1118 - of about 32 iteration
crash ~ :)

我发现问题是由 proc 引起的,它将 image_path 添加到数据库并在需要特殊格式时调整其大小(在 html 输入解析期间)

所以在调试器中,我按照命令运行以检查 ruby​​ 保存的文件。

ObjectSpace.each_object(File){ |f| puts f.path }

我发现上传了 50 个名称包括“RackMultipart”的文件,并且在迭代后 tmp 文件夹中的文件数被具有奇怪名称的新文件(可能是回形针临时文件)所记入。 我认为 peperclip 或某些应用程序代码不会关闭文件,所以在 proc 结束时我添加了以下代码:

        now = Time.now.to_formatted_s( :number )[0..7]
        ObjectSpace.each_object(File).map do |f|
          if f.path.include?( "/tmp/" ) && !f.closed?
            unless f.path.include? "RackMultipart#{now}"
              f.close
              f = nil
            end
          end
        end

在那之后什么都没有发生。在调试器中我运行了命令

ObjectSpace.each_object(File){ |f| puts ( f.closed? '+' : '-' ) }

打开文件的数量 (-) 是正确的 (~160),但命令仍然列出关闭的文件。我关闭它们后它们不应该消失吗?

截断的方法如下所示:

def function(g, files)

    ...

    asset = proc do |img|
      ...
      file = files.find{|f| f.original_filename == src}
      if file

        geo = Paperclip::Geometry.from_file file.path

        if(geo.width <= 20 && geo.height <= 20)
          ...
        else
          asset = figure.assets.build
          asset.file = file ## HERE RUNS
          ...
        end

        now = Time.now.to_formatted_s( :number )[0..7]
        ObjectSpace.each_object(File).map do |f|
          if f.path.include?( "/tmp/" ) && !f.closed?
            unless f.path.include? "RackMultipart#{now}"
              f.close
              f = nil
            end
          end
        end
      else
        ...
      end
    end

    ...

      while img = g.find_first(".//img")
        asset.call(img) # !HERE HAPPENS
        img.remove!
      end

 end # end function

资产模型定义:

class Asset < ActiveRecord::Base
  ...

  has_attached_file :file, url: "/system/:class/:attachment/:id/:style_:filename",
                    styles: lambda { |attachment| attachment.instance.switch_styles },
                    :convert_options => {medium: lambda{|asset| asset.is_table? ? "-units PixelsPerInch -resample 120 -strip" : "-strip"}, 
                                            all: '-strip'}




  validates_attachment :file, content_type: { content_type: ["image/jpg","image/png","image/gif","image/jpeg","image/tiff"] },
                       size: { in: 0..10.megabytes }

  def is_table?
    ...
  end

  def switch_styles
    self.file.content_type == "image/tiff" ?
    { backup: "100%", original: ["100%", :png], medium: [self.is_table? ? "" : "800x600>", :png], small: ["300x300>", :png], formula: ['50%', :png] } :
    { medium: self.is_table? ? "" : "800x600>", small: "300x300>", formula: '50%' }
  end

end

希望你能理解我写的内容;)

提前感谢 4 您的帮助。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3.2 paperclip


    【解决方案1】:

    好的。这段代码没有问题,一切正常。但是有时有人在父父类中禁用了 GarbageColector。可能是为了加快解析过程。 所以现在当文件数量超过 ulimit 的 70% 时,我会打开 GC,如果它清理了不必要的临时文件,我会再次将其关闭。


    编辑: 运行然后再次禁用 GC 的函数

      def gc_check
        if ObjectSpace.each_object(File).to_a.size > 850  
          GC.start if GC.enable
        else
          GC.disable
        end
      end
    

    希望对你有所帮助。

    【讨论】:

    • 不幸的是我不能。对不起。第一篇文章中的代码包含上传图片的所有重要内容其余是我们公司的解决方案。
    • 检测到 70% 的 ulimit 时的部分呢.../
    • 答案中添加了代码示例。
    猜你喜欢
    • 2015-05-09
    • 2017-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-29
    • 1970-01-01
    相关资源
    最近更新 更多