0

我在回形针附件模型中添加了两种样式(小卡和中卡)截图:

class Screenshot < ActiveRecord::Base
    has_attached_file :image,
    :styles => { :tiny => "x75", :small => "x245", :medium => "x480", :large => "1280x900>",
                 :smallcard => "280x245#", :mediumcard => "570x480#" },
    :storage => :s3,
    :s3_credentials => "#{Rails.root}/config/amazon_s3.yml",
    :path => "/screenshots/:id_partition/:style/:filename"
end

我手动创建了一个 public/system/paperclip_attachments.yml 文件以减少对预先存在的样式的处理:

---
:Screenshot:
  :image:
    - :tiny
    - :small
    - :medium
    - :large

但是当我运行 rake paperclip:refresh:missing_styles CLASS=Screenshot 时,我得到以下信息:

Regenerating Screenshot -> image -> [:mediumcard, :smallcard]
rake aborted!
Cannot allocate memory - identify -format %wx%h '/tmp/79a229e96ab52dfa760132958da47bf320120806-31260-1eleoww[0]'
Tasks: TOP => paperclip:refresh:missing_styles
[clip]

当我跟踪日志时,处理只达到 500 秒(id)。

该服务器无疑是一台运行 Ubuntu 的 Linode 512,多年来它在为 3 个 Rails 应用程序和 1 个 PHP 应用程序提供页面服务方面表现出色。我以前从来没有用过它的内存。

监视 rake 任务进程,它随着每个处理的图像而递增,直到它吃光所有可用的 RAM。

也许是时候让我的 Linode 成长了……但首先我希望有其他选择。

如何解决此内存问题并将这两种样式添加到预先存在的 13k 图像中?

谢谢你的帮助!

4

2 回答 2

2

您需要让系统有机会正确释放内存。我们在遇到使用 ORM 处理 PHP 批处理任务的类似问题时使用的一个大胆技巧是:将您的任务包装在另一个任务中,该任务一次只为一个项目调用第一个任务。通常,您应该重构第一个任务以获取基本映像的参数。第二个任务应该收集所有图像(以内存友好的方式,例如对象 ID 或类似的东西),然后遍历它们并以每个作为参数调用第一个任务。当第一个任务完成时,它将内存返回给操作系统,然后可以释放内存。另一方面,第二个或包装任务从不一次需要那么多内存。这样,最大内存使用量应该是处理一张图像的最大值,而不是全部图片。

于 2012-08-06T21:53:35.857 回答
0

希望这可以帮助其他有同样问题的人。

正如 Chris 建议的那样,我将一个 rake 任务包裹在另一个使用 %x() 调用的任务中。每次迭代都会完全释放上一次调用的内存。

namespace :screenshots do
  desc "Incrementally rebuild thumbnails. START=0 & BATCH_SIZE=10 & VERBOSE=false"
  task :reprocess_stepper => :environment do
    batch_size = (ENV['BATCH_SIZE'] || ENV['batch_size'] || 10)
    verbose    = (ENV['VERBOSE'] || ENV['verbose'] || nil)

    total = Screenshot.count
    start = 0

    while start < total
      puts "Spawning: bundle exec rake screenshots:reprocess_some START=#{start} BATCH_SIZE=#{batch_size} VERBOSE=#{verbose} RAILS_ENV=#{Rails.env}"
      puts %x{bundle exec rake screenshots:reprocess_some START=#{start} BATCH_SIZE=#{batch_size} VERBOSE=#{verbose} RAILS_ENV=#{Rails.env} }
      start = start + batch_size.to_i
    end
  end

  desc "Reprocess a batch of screenshots. START=0 & BATCH_SIZE=10 & VERBOSE=false"
  task :reprocess_some => :environment do
    start      = (ENV['START'] || ENV['start'] || 0)
    batch_size = (ENV['BATCH_SIZE'] || ENV['batch_size'] || 10)
    verbose    = (ENV['VERBOSE'] || ENV['verbose'] || nil)

    puts "start = #{start} & batch_size = #{batch_size}" if verbose
    puts "RAILS_ENV=#{Rails.env}" if verbose

    screenshots = Screenshot.order("id ASC").offset(start).limit(batch_size).all
    screenshots.each do |ss|
      puts "Re-processing paperclip image on screenshot ID: #{ss.id}" if verbose
      STDOUT.flush
      ss.image.reprocess!
    end
  end
end

然后,您可以按如下方式调用此任务:

RAILS_ENV=production bundle exec rake screenshots:reprocess_stepper VERBOSE=true BATCH_SIZE=50
于 2012-09-02T18:47:20.973 回答