4

乍一看,我敢肯定这个标题听起来像是一个已经被问过一百万次的问题……但事实并非如此。

我的应用程序确实使用了数据库,但只有应用程序的某些部分实际上依赖于正在启动和运行的数据库。我想确保如果/当数据库关闭时,不依赖于数据库的应用程序部分仍然可以正常运行。

问题是......一旦 Rails 应用程序意识到它失去了它的数据库连接,应用程序的任何部分(除了静态内容)都无法工作。(即在执行流程到达不依赖于数据库的控制器之前抛出异常 - 如果允许这样做,控制器会做得很好。)

有没有办法实现我正在寻找的东西?任何帮助表示赞赏!

更新:

经过一番仔细检查,我相信问题归结为:

是否有一种使用“惰性”数据库连接池/处理的方法,以便在绝对需要之前不会将数据库连接从池中检出?如果可能,这将允许根本不使用数据库的请求继续进行,即使/当数据库关闭时也是如此。

想法?

更新 2:

添加堆栈跟踪。这表明当数据库连接不可用时,控制永远不会到达控制器。(数据库显然是故意关闭的,所以我可以测试一下。)

PG::Error
could not connect to server: Connection refused Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5432?
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/postgresql_adapter.rb:771:in `initialize'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/postgresql_adapter.rb:771:in `new'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/postgresql_adapter.rb:771:in `connect'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/postgresql_adapter.rb:493:in `initialize'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/postgresql_adapter.rb:41:in `new'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/postgresql_adapter.rb:41:in `postgresql_connection'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:446:in `new_connection'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:456:in `checkout_new_connection'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:427:in `acquire_connection'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:364:in `block in checkout'
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:363:in `checkout'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:273:in `block in connection'
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/monitor.rb:211:in `mon_synchronize'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:272:in `connection'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:552:in `retrieve_connection'
activerecord (4.0.0.beta1) lib/active_record/connection_handling.rb:79:in `retrieve_connection'
activerecord (4.0.0.beta1) lib/active_record/connection_handling.rb:53:in `connection'
activerecord (4.0.0.beta1) lib/active_record/query_cache.rb:51:in `restore_query_cache_settings'
activerecord (4.0.0.beta1) lib/active_record/query_cache.rb:43:in `rescue in call'
activerecord (4.0.0.beta1) lib/active_record/query_cache.rb:32:in `call'
activerecord (4.0.0.beta1) lib/active_record/connection_adapters/abstract/connection_pool.rb:632:in `call'
actionpack (4.0.0.beta1) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.0.0.beta1) lib/active_support/callbacks.rb:373:in `_run__2745032424595922925__call__callbacks'
activesupport (4.0.0.beta1) lib/active_support/callbacks.rb:78:in `run_callbacks'
actionpack (4.0.0.beta1) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.0.0.beta1) lib/action_dispatch/middleware/reloader.rb:64:in `call'
actionpack (4.0.0.beta1) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
actionpack (4.0.0.beta1) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
actionpack (4.0.0.beta1) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.0.0.beta1) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.0.0.beta1) lib/rails/rack/logger.rb:21:in `block in call'
activesupport (4.0.0.beta1) lib/active_support/tagged_logging.rb:67:in `block in tagged'
activesupport (4.0.0.beta1) lib/active_support/tagged_logging.rb:25:in `tagged'
activesupport (4.0.0.beta1) lib/active_support/tagged_logging.rb:67:in `tagged'
railties (4.0.0.beta1) lib/rails/rack/logger.rb:21:in `call'
actionpack (4.0.0.beta1) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
rack (1.5.2) lib/rack/runtime.rb:17:in `call'
activesupport (4.0.0.beta1) lib/active_support/cache/strategy/local_cache.rb:72:in `call'
rack (1.5.2) lib/rack/lock.rb:17:in `call'
actionpack (4.0.0.beta1) lib/action_dispatch/middleware/static.rb:64:in `call'
railties (4.0.0.beta1) lib/rails/engine.rb:510:in `call'
railties (4.0.0.beta1) lib/rails/application.rb:96:in `call'
rack (1.5.2) lib/rack/lock.rb:17:in `call'
rack (1.5.2) lib/rack/content_length.rb:14:in `call'
rack (1.5.2) lib/rack/handler/webrick.rb:60:in `service'
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/webrick/httpserver.rb:138:in `service'
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/webrick/httpserver.rb:94:in `run'
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/webrick/server.rb:295:in `block in start_thread'
4

3 回答 3

1

很抱歉,我正在回答有关 Rails 3 的问题,但我希望它会有所帮助。

我在有点不同的情况下遇到了同样的问题,所以我挖掘了堆栈跟踪和 Rails 代码,并找出了如何用两行来修复它。

TL;博士:

# config/application.rb
# before your application declaration
ActiveRecord::Railtie.initializers.reject! { |i| i.name == 'active_record.set_reloader_hooks' }
# inside your application declaration
config.middleware.delete ActiveRecord::QueryCache

首先,当 rails 启动时,它会调用ActionDispatch::Reloader.prepare!(一次用于生产,每个请求用于开发)。这种方法就像单元测试中的设置,它重置了很多东西,其中包括从连接池中清除连接并清除模式缓存,后者从池中检查数据库连接。所以第一行删除了active_record/railtie添加回调的初始化程序。可能您只想为生产环境执行此操作,但此修改应该在application.rb或以上才能工作。

其次,rails 确实会在每个请求上检查数据库连接,但这是在ActiveRecord::QueryCache中间件中完成的。我决定我可以没有它。如果你真的需要它,我认为你可以在around_filter.

于 2014-12-02T23:39:14.867 回答
0

您可以使用以下命令从控制器中的数据库错误中解救出来

rescue_from ActiveRecord::StatementInvalid do |e|
  logger.info 'ActiveRecord error ignored in databaseless controller:'
  logger.info e.message
end

Rescuing fromActiveRecord::StatementInvalid可能会涵盖所有您想忽略的数据库异常,但您必须自己弄清楚。文档指出ActiveRecord::StatementInvalid在以下情况下会抛出:

当数据库无法执行 SQL 语句时引发(例如,当使用的 Ruby 驱动程序太旧时,MySQL 经常出现这种情况)。

否则,您也可以从更通用的超类中解救出来,ActiveRecord::ActiveRecordError但这将涵盖所有Active Record 错误,并且可能不是您想要的。

编辑:这将无法处理您根本没有连接的情况,因此在您的情况下它基本上没用。如果其他人应该寻找这个,我仍然会在这里保留答案。

于 2013-06-13T07:10:31.453 回答
0

您可能想要做的是与上述类似的事情。创建一个父控制器,它的所有继承控制器都是那些不需要数据库访问的控制器。用于rescue_from抓取那些数据库错误(StatementInvalid在本例中)

class DbDontCare < ApplicationController
  rescue_from ActiveRecord::StatementInvalid do |exception|
    # do some logging or whatever
  end
end

接下来,将需要保护的控制器添加到此范围

class IHateDb < DbDontCare
end

等等。

您可能需要rescue_from在父控制器中添加多个定义来处理所有可能的异常。

于 2013-06-13T07:50:29.770 回答