まず、私の下手な英語をお詫びしたいと思います。
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 個のファイルを開くことができます。それで、私はコマンドを実行しました:
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 ~ :)
問題は、データベースにimage_pathを追加し、特別なフォーマットが必要な場合はサイズを変更するprocによって引き起こされることがわかりました(html入力解析中)
そのため、デバッガーで次のコマンドを実行して、ルビーが保持するファイルを確認しました。
ObjectSpace.each_object(File){ |f| puts f.path }
「RackMultipart」を含む名前でアップロードされた 50 個のファイルがあり、反復後に 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 よろしくお願いします。