2013-06-13 2 views
4

На первый взгляд, я уверен, что название заставляет это звучать как вопрос, который задавали миллионы раз раньше ... но это не так.Контроллеры Rails без базы данных

Мое приложение Использует базу данных, но только некоторые части приложения фактически полагаются на базу данных, которая работает и работает. Я хотел бы убедиться, что части приложения, которые НЕ зависят от базы данных, могут работать правильно, если/когда база данных не работает.

Проблема заключается в том, что, как только приложение Rails осознает, что оно потеряло соединение с базой данных, НИКАКАЯ часть приложения (за исключением статического контента) не работает. (т. е. исключение выбрасывается до того, как поток выполнения когда-либо достигнет контроллера, который не зависит от базы данных - контроллер, который будет очень хорошо, если бы ему было разрешено это делать.)

Есть ли способ достичь что я ищу? Любая помощь приветствуется!

Update:

После некоторого тщательного изучения, я считаю, что вопрос сводится к следующему:

Есть ли средство использования «ленивое» соединение с базой данных объединения/обработки таким образом, что соединение с базой данных ISN Не проверен ли он из бассейна, пока он не понадобится? Если возможно, это позволит запросам, которые вообще не используют базу данных, продолжать, даже если/когда база данных не работает.

Мысли?

Обновление 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' 
+0

Rails резервирует соединение с db по каждому запросу. Я уверен, что должен быть способ отключить это (возможно, промежуточное ПО где-то?), Но, возможно, этого не будет. Вы можете попробовать записать эти биты в микрофрейм, например, Sinatra вместо Rails (который затем можно подключить к вашему рельсовому приложению) – cpuguy83

+0

Я не думаю, что Rails вызывает БД, если это не нужно. Это потому, что вы сохраняете сеансы в БД? – oldergod

+0

Я бы порекомендовал вам получить подробную информацию по этой теме: http://guides.rubyonrails.org/initialization.html#back-to-railties-lib-rails-all-rb. Следующим шагом будет просмотр конфигурации '' 'config/application.rb''' и директивы' 'require 'rails/all" '' '. Вы могли бы посмотреть, как мангоид избегает немедленной инициализации activerecord: http://mongoid.org/en/mongoid/docs/installation.html#installation – icanhazbroccoli

ответ

0

Вы можете спасти от ошибок базы данных в контроллерах с

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

спасая от ActiveRecord::StatementInvalid, вероятно, охватывать все эти исключения базы данных, которые вы хотите игнорировать, но вам придется это понять самостоятельно. The documentation утверждает, что ActiveRecord::StatementInvalid выбрасывается в следующем случае:

Воспитанный, когда SQL заявление не может быть выполнена в базе данных (для например, это часто бывает для MySQL, когда водитель Рубин используется слишком старый).

В противном случае вы могли бы также спасти от более общего суперкласса ActiveRecord::ActiveRecordError, но который будет охватывать все Активных ошибок Записи и, вероятно, не то, что вы хотите.

Редактировать: Это не будет обрабатывать случай, когда у вас нет соединения вообще, поэтому оно практически бесполезно в вашем случае. Я по-прежнему буду отвечать на этот вопрос, если кто-то еще должен это искать.

+0

спасибо за предложение, но это не сработает. Я наблюдаю, что Rails резервирует соединение с базой данных (проверяет его из пула) задолго до того, как запрос когда-либо перенаправляется на контроллер (это происходит в промежуточном программном обеспечении). Независимо от того, какая обработка исключений встроена в контроллер, это не будет иметь никакого эффекта. Запомните еще раз, я использую Rails 4, хотя я считаю, что это верно для 3.2.x также. –

+0

Я добавил трассировку стека к своему оригинальному сообщению, чтобы вы могли видеть, что я имею в виду. –

+0

Согласно трассировке стека, он, возможно, должен спасти от 'PG :: Error'. – pduersteler

0

то, что вы, вероятно, хотите сделать, похоже на вышеизложенное. создайте родительский контроллер, чтобы все его наследованные контроллеры были теми, кому не нужен доступ к db.использовать 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 в ваш родительский контроллер для обработки всего возможных исключений.

+0

спасибо за предложение, но обратите внимание, что в трассировке стека управление никогда не достигает контроллера или ЛЮБОГО кода приложения. Это исключение выбрасывается из рамок в самом начале жизненного цикла запроса. –

+0

Из того, что я читал до сих пор, нет реального способа сделать это для части вашего приложения, вы можете полностью удалить активную запись, но это не поможет вам. вы подумали о том, чтобы разбить его на 2 разных приложения и взаимодействовать через интерфейс RESTful? –

+0

Это, к сожалению, не очень удобное решение проблемы. Если я разбиваю его на два приложения, как же я могу поделиться шаблонами, помощниками и т. Д.? Это логически одно приложение. –

1

Прошу прощения, что я отвечаю о Rails 3, но я надеюсь, что это поможет немного.

У меня такая же проблема в немного разных обстоятельствах, поэтому я выкопал код stacktraces и rails и выяснил, как исправить его в двух строках.

TL; DR:

# 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 

Во-первых, когда рельсы сапоги, он вызывает ActionDispatch::Reloader.prepare! (один раз для производства, каждый запрос на разработку). Этот метод похож на установку в модульных тестах, он сбрасывает многие вещи, среди прочего, он очищает соединения из пула подключений и очищает кеш схемы, а последний проверяет соединение БД из пула. Таким образом, первая строка удаляет инициализатор в active_record/railtie, который добавляет этот обратный вызов. Вероятно, вы хотели бы сделать это только для производственной среды, но эта модификация должна быть в application.rb или выше для работы.

Во-вторых, рельсы действительно проверяют соединение БД по каждому запросу, но это делается в промежуточном программном обеспечении ActiveRecord::QueryCache. Я решил, что смогу обойтись без него. Если вам это действительно нужно, я думаю, вы можете включить и сбросить кеш в around_filter.

Смежные вопросы