小编Jen*_*ens的帖子

跟踪Ruby on Rails 3/Postgres/Apache Passenger应用程序中的内存泄漏

你好,

我们最近更新了一个应用程序到Rails 3.0.4(在线开发服务器上的3.0.5).从2.3.10到3.0.4的大多数变化都是由于过时或过时的插件和宝石,并且相对容易解决.但有一件事让我发疯:

在开发模式下,每个Web请求都会导致服务器进程分配比以前 50-60 MB的内存.请求后释放此内存,至少不是全部内存.在10-20个请求之后,每个Ruby实例消耗超过500 MB的RAM,而我们以前的Rails 2.3.10实例很少超过200 MB.

这使得无法运行我们的1300次测试,因为在测试结束之前,开发了4GB的RAM.它只发生在开发模式中cache_classes = false.如果我将cache_classes切换为true,Rails实例将消耗大约200MB的内存,然后保留在那里.但是,在测试期间,即使cache_classes = true,内存使用量也会增加.

我查询了ObjectSpace并发现每次请求时,大约有3500个新的Proc,最多50'000个新的Strings和3000个新的Hashes和Arrays被创建并且没有被释放.这些字符串(转储时)包含我的整个源代码,包括插件和gem,文档,源代码注释和路径名.(为什么?)

为了找到原因,这是我尝试过的:(每次更改后,我都会使用ab -n 50.)

  1. 我用一个资源和控制器以及SQLite3 DB 创建了一个全新的Rails 3应用程序.内存使用量从60 MB开始,并保持在80 MB以下.
  2. 我将'sqlite3'更改为'pg'并将新的Rails 3应用程序指向我现有的Postgres DB.内存使用量从110 MB开始,并没有超过130MB.(旁边的问题:为什么Postgres gem使用比SQLite3 gem更多的内存?)
  3. 我将我的Gemfile和Gemfile.lock从破碎的Rails3应用程序复制到裸骨应用程序并运行bundle install.没有变化,无论提出多少请求,内存都保持在115MB左右.
  4. 我在破碎的Rails3应用程序中创建了一个空的"def FooController; def foo; render:text =>'foo'end; end".内存使用量增长缓慢,但在请求后仍然没有停止增长.
  5. 我删除了除FooController路由之外的所有路由.没有变化.
  6. 我禁用了所有Gems,除了以下内容:pg, rails, aasm, will_paginate, geokit-rails3, koala, omniauth, paperclip …

postgresql memory-leaks rspec-rails ruby-on-rails-3

15
推荐指数
1
解决办法
3892
查看次数

Rails 3,RSpec 2.5:使用带有命名范围的should_receive或stub_chain

我使用Rails 3.0.4和RSpec 2.5.例如,在我的控制器中,我大量使用命名范围

   @collection = GuestbookEntry.nonreplies.bydate.inclusive.paginate(
       :page => params[:page], :conditions => { ... })

在我的测试中,我希望能够模拟这种查询的结果,而不是措辞.我觉得做某事并不合理

   GuestbookEntry.stub_chain(:nonreplies, :bydate, ...).and_return(...)

因为当我决定重新排序命名范围时,此测试将失败.

使用Rails 2.3和RSpec 1.x,这很好用:我可以写

   GuestbookEntry.should_receive(:find).with(:all, :conditions => { ... })

并且上述调用将被捕获并正确处理.然而,使用Rails 3,由于某种原因,这不再起作用.

为什么?如何设置嵌套范围结果的期望值或存根?由于Rails 3的ActiveModel中的所有内容都是命名范围(感谢ARel),因此必须以某种方式实现,否则测试确实非常脆弱.

谢谢!

更新:另请参阅GitHub上的问题报告.

bdd activemodel arel rspec2 ruby-on-rails-3

12
推荐指数
1
解决办法
1803
查看次数

Ruby on Rails:Bundler和Capistrano:指定在部署时要排除哪些组(开发,测试)

Bundler文档说,为了在通过Capistrano部署时安装所有必需的bundle,只需插入即可

require 'bundler/capistrano' # siehe http://gembundler.com/deploying.html
Run Code Online (Sandbox Code Playgroud)

在他的deploy.rb中.然后,在部署时,Capistrano打电话

  * executing "bundle install --gemfile .../releases/20110403085518/Gemfile \
    --path .../shared/bundle --deployment --quiet --without development test"
Run Code Online (Sandbox Code Playgroud)

这很好用.

但是,我们的生产服务器上有一个分段设置,与真实的实时站点隔离,我们在那里测试带有(克隆和防火墙)实时生产数据的新应用程序版本.在那里,我们需要安装测试和开发宝石.

如何在此处指定capistrano命令行?是否有我可以使用的参数,或者我是否需要设置自己的capistrano任务来覆盖Bundler?

谢谢!

production capistrano ruby-on-rails staging bundler

8
推荐指数
1
解决办法
4333
查看次数

Ruby on Rails 3:结合多个has_many或has_many_through关联的结果

我有以下型号.用户有UserActions,一个可能的UserAction可以是ContactAction(UserAction是一个多态).还有LoginAction等其他动作.所以

 class User < AR::Base
  has_many :contact_requests, :class_name => "ContactAction"
  has_many :user_actions
  has_many_polymorphs :user_actionables, :from => [:contact_actions, ...], :through => :user_actions
 end

class UserAction < AR::Base
 belongs_to :user
 belongs_to :user_actionable, :polymorphic => true
end

class ContactAction < AR::Base
 belongs_to :user
 named_scope :pending, ...
 named_scope :active, ...
end

这个想法是一个ContactAction加入两个用户(在应用程序中有其他后果),并始终有一个接收端和一个发送端.同时,ContactAction可以具有不同的状态,例如过期,待定等.

我可以说@user.contact_actions.pending@user.contact_requests.expired列出用户发送或接收的所有待处理/过期请求.这很好用.

我现在想要的是一种加入两种类型的ContactAction的方法.即@user.contact_actions_or_requests.我尝试了以下方法:

class User

 def contact_actions_or_requests
  self.contact_actions + self.contact_requests
 end

 # or
 has_many :contact_actions_or_requests, :finder_sql => ..., :counter_sql => ...

end

但是所有这些都存在这样的问题:在关联之上不可能使用额外的finder或named_scopes,例如@user.contact_actions_or_requests.find(...)或 …

polymorphism ruby-on-rails associations has-many-polymorphs

6
推荐指数
1
解决办法
2461
查看次数

将复杂的has_many关系移植到Rails> 4.1(没有finder_sql)

我正在将Rails应用程序移植到Rails 4.2.这个Rails应用程序在关联中包含一些相当复杂的手动SQL代码 - 部分是由于DB优化(例如子选择而不是JOIN),部分原因是由于在编写时没有可行的替代方案(Rails 3.0),部分原因是由于缺乏知识(我希望,至少 - 这很容易解决).

示例:InternalMessage类.可以在用户之间发送消息(InternalMessage的收件人和消息的"删除",存储在InternalMessagesRecipients中,因为可以有几个)并且可以读取,回复,转发和删除它们.该关联看起来像这样:

class User < AR::Base
  has_many :internal_messages,
      :finder_sql => "SELECT DISTINCT(internal_messages.id), internal_messages.* FROM internal_messages " +
          ' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' +
          ' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}',
      :counter_sql => 'SELECT count(DISTINCT(internal_messages.id)) FROM internal_messages ' +
          ' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' +
          ' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}'
  # ...
end
Run Code Online (Sandbox Code Playgroud)

关键部分是最后的"OR"子句 - 通过这种关联,我希望获得接收和发送的消息,这些消息与用户表单独连接:

  has_many :sent_messages, -> { where(:sender_deleted_at => nil) }, :class_name => 'InternalMessage', …
Run Code Online (Sandbox Code Playgroud)

activerecord ruby-on-rails finder-sql model-associations

5
推荐指数
1
解决办法
2784
查看次数

Postgres SQL:当表具有开始日期和结束日期列时,每个日期获得一个结果

这有点类似于PostgreSQL中的获取日期列表,但不完全相同(我认为).

我有一个SQL表,其中每一行都包含一个开始和结束日期.我想形成一个查询,以便对于每一行,对于此范围内的每个日期,我得到一个结果.

例如: id=1, title=MyRange, start=2012-08-05, end=2012-08-08

查询: SELECT * FROM myTyble where id=1 AND ...

结果:

 id=1, title=MyRange, date=2012-08-05
 id=1, title=MyRange, date=2012-08-06
 id=1, title=MyRange, date=2012-08-07
 id=1, title=MyRange, date=2012-08-08
Run Code Online (Sandbox Code Playgroud)

我意识到在这个结果集中将复制唯一和主键行,但这对我来说无关紧要.任何想法都会非常受欢迎!

sql postgresql date range

4
推荐指数
1
解决办法
498
查看次数

Rails 3:在模块中使用'before_create'(对于ActiveRecord模型)

我正在编写一个应用程序,其中许多(但不是全部)ActiveRecord模型都有一hash列.这是使用随机MD5哈希创建时填充的,用于引用单个对象而不是其ID.为实现这一目标,我在相应的型号中包含了以下模块,并find_by_id_or_hash!()在所有控制器中使用而不是find:

module IdOrHashFindable

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods

    before_create :create_hash             ## <-- THIS FAILS

    # legacy. in use only until find by ID is phased out altogether
    def find_by_id_or_hash!(id_or_hash)
      id_or_hash.to_s.size >= 32 ? find_by_hash!(id_or_hash) : find(id_or_hash)
    end
  end

  def to_param; self.hash end
  def create_hash; self.hash = Support.create_hash  end

end
Run Code Online (Sandbox Code Playgroud)

为了保持干燥,我想before_create在模块内部进行调用.但是,我一直在努力

undefined method `before_create' for IdOrHashFindable:Module
Run Code Online (Sandbox Code Playgroud)

要么

undefined method `before_create' for IdOrHashFindable::ClassMethods:Module
Run Code Online (Sandbox Code Playgroud)

取决于我把它放在哪里.这是有道理的(毕竟,我正在调用一个函数,而不是定义它),但我仍然想知道如何做到这一点.(before_create因为还有其他before_create调用,我无法覆盖).

此外,对于包含此模块的所有型号,都应用非常类似的测试.我如何持续测试此功能?我是否将自定义describe ... end块 …

ruby activerecord module ruby-on-rails-3

2
推荐指数
1
解决办法
1839
查看次数