Mysql 在RubyonRails中使用fork创建并行进程

Mysql 在RubyonRails中使用fork创建并行进程,mysql,ruby,ruby-on-rails-3,fork,mysql2,Mysql,Ruby,Ruby On Rails 3,Fork,Mysql2,我有一个Rails 3应用程序正在生产中,在Apache上有乘客。我有以下代码: class Billing < ActiveRecord::Base after_save :sendEmails private def sendEmails fork do UserMailer.clientBilling(self.user, self).deliver end end end 类计费

我有一个Rails 3应用程序正在生产中,在Apache上有乘客。我有以下代码:

class Billing < ActiveRecord::Base
  after_save :sendEmails

  private
    def sendEmails
      fork do 
        UserMailer.clientBilling(self.user, self).deliver
      end
    end
end
类计费

在localhost中,当应用程序创建账单时,保存后,应用程序会向用户发送电子邮件,一切正常。但在服务器上,应用程序创建账单后,会抛出与gem MySQL2相关的错误,如“MySQL服务器已离开”或“连接丢失”,并且应用程序不会发送电子邮件。如果我删除fork,它可以正常工作,但我想使用fork,我想创建一个单独的过程,因为发送电子邮件需要很长时间。有什么问题吗?

在使用带有导轨/乘客的叉子时要格外小心,它可能会变得非常凌乱!相反,您应该使用此任务

问题是分叉进程继承了其父进程的一些资源,例如其文件描述符。特别是一个这样的共享资源是MySQL连接。当子进程完成其电子邮件发送并退出时,它将关闭MySQL连接,这将关闭父进程连接

如果你继续沿着这条路走下去(这条路也有类似的微妙之处),那么你需要这样做:

#在分叉之前清除现有连接,以确保它们不会被继承。
::ActiveRecord::Base.clear_所有连接!
叉子
#为每个分叉建立新连接。
::ActiveRecord::Base.build\u连接
#每个fork的其余代码。。。
结束

如果您使用memcached或mongodb等服务,则必须对其执行类似操作。

您可以在fork内部重新建立连接:

dbconfig = YAML::load(File.open('your_app_dir/config/database.yml'))
ActiveRecord::Base.establish_connection(dbconfig['development'])

您知道哪些资源是继承的吗?我以为一个过程复制了整个过程?整个rails环境不是再次加载到一个fork上吗?它复制了整个过程,但文件描述符引用了完全相同的文件(请参阅fork的手册页)。我发现,
建立连接并不总是必要的,因为ActiveRecord通常会透明地管理它。我认为ActiveRecord现在会自动执行此操作,但我认为这是一个相对较新的问题change@FrederickCheung你真是个天才。很好地解释了它,而不仅仅是提供了一个解决方案。这个解释很有道理。甚至(特别是?)在2021年。谢谢我花了7天时间才发现错误消息“Mysql::error:在查询过程中与Mysql服务器失去连接”和“Mysql::error:Mysql服务器已离开”是使用fork的结果。