ActiveRecordã®DBã³ãã¯ã·ã§ã³ã®æ¥ç¶åãã¨åæ¥ç¶ã«ã¤ãã¦ãreconnectãªãã·ã§ã³ã¯å±éºã ãªã¼ã¨ãã
ActiveRecordã¯åºæ¬ãã£ã¨æ¥ç¶ãã¯ãã£ã±ãªãã«ãã¾ãã
ãªã®ã§é·æéæ¥ç¶ãã¯ãã£ã±ãªãã«ãããã
ã¿ã¤ã ã¢ã¦ãçã§æ¥ç¶ããããã¨åé¡ãã§ã¾ãã
MySQLでDBの接続がきれるタイミング
ç¶æ³å¥
- Railsã®å ´å
- HTTPãªã¯ã¨ã¹ãã®ãããã³ã«æ¥ç¶ãåãã¦ãªããã確èªãã¾ããåãã¦ãå ´åã¯åæ¥ç¶ããããã«ãªã£ã¦ããã®ã§åé¡ãªãããã§ãã
- ãããããã¼ã¢ã³ç
- ActiveRecordã使ã£ãå ´åã¯ãã£ã¨ã¤ãªãã£ã±ãªãã«ãªããããéä¸ã§æ¥ç¶ãåããã¨ã¨ã©ã¼ã«ãªãã¾ãã
reconnectãªãã·ã§ã³ã¯å±éº
ããããããçã®å ´åèªåã§åæ¥ç¶ãã¦ãããã°ã¨æãã¨
MySqlã®ã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªã¬ãã«ã§ãªã³ãã¯ãã®æ¦å¿µãããã¾ããã
railsã§ä½¿ãã«ã¯database.ymlã«:reconnect = trueã§æå®ã§ãã¾ãã
ãï¼ï¼
railsã®å®è£
ã§ã¯ããã©ã«ãã¯OFFã«ãªã£ã¦ãã¾ãã
ãªãã§OFFããªã¨ããã£ããä¸è¨ã®ãã¼ã¸ãè¦ããç´å¾ãã¾ããã
http://dev.mysql.com/doc/refman/5.1/ja/mysql-reconnect.html
å¤æ°ã使ã£ããããå ´åçã®æ¥ç¶ã»ãã·ã§ã³ã«ä¾åãããããªå ´åã®ã³ã¼ããæ¸ãã¨ãéä¸ã§æ¥ç¶ãããã¦å¤æ°çããªã»ããããã¦ãã®ã«ãã¥ããã«æ¬¡ã®å¤æ°çã«ä¾åããsqlãå®è¡ãã¦ãã¾ãå¯è½æ§ãããããã§ãã
ãã©ã³ã¶ã¯ã·ã§ã³å¨ããå±éºã£ã½ãã§ããããã¼ã«ããã¯ãã¦ãã®ã«æ°ã¥ããèªåã³ãããã«æ»ã£ã¦å®è¡ããã¡ããã¨ãããªã¼ãæãæãã
ãªã®ã§ãã®èªååæ¥ç¶ã¯ä½¿ããªãã»ãããããã¨ã
ãããçã®å ´åã§ã®å¯¾ç
åããå¯è½æ§ã¯
ã¾ãã¼æ®éã¯LANãªã®ã§ãããªæ¥ç¶ã¯åããªãã ããã¨ããåæã§æ°ã«ããªãã§ã¨ã©ã¼ã«ãªã£ã¦ãããã¨æãã¾ãã
ä½ãããããã«ãã£ã¦ã¯éãå¦ççããããã¨ãããã§ããããã
MySQLでDBの接続がきれるタイミングã«æ¸ããããã«
éãéè¨å¦çããã¦ããã¤ã³ãµã¼ãããå ´åçããSQLèªä½ãã²ãéãªå ´åçã
ã§æ¥ç¶ãåããå¯è½æ§ãããã¾ãï¼ç¹ã«SLBçµç±ã®DBã¢ã¯ã»ã¹ã®å ´åï¼ã
ããã¾ããªãã¨ã¯æãã¾ããVPNçµç±ã§DBæ¥ç¶ãã¦ã¦åç·ãä¸å®å®ã§ç¬æããããããã¨ããããããããã¾ããã
対ç
- VPNçµç±ã§DBæ¥ç¶ã®å ´åçã®ç¬æ
- ãã®ãããªå ´åã«ã¯rescueã§æ¾ã£ã¦ãããªããã«ããã®ãè¯ãããããã¾ããã
- 注æç¹ã¨ãã¦ããç´ãããåã«ActiveRecord::Base.clear_active_connections!ãå¼ã¶å¿ è¦ãããã¾ãã
- ãã®ã¡ã½ãããå¼ã¶ãã¨ã§æ¥ç¶ãã£ã±ãªãã®ã³ãã¯ã·ã§ã³ãä¸æ¦ã³ãã¯ã·ã§ã³ãã¼ã«ã«è¿å´ãã¦æ¬¡ã®ã³ãã¯ã·ã§ã³ä½¿ç¨æã«åæ¥ç¶ãã¦ãããã¾ãã
- éãéè¨å¦çããã¦ããã¤ã³ãµã¼ãããå ´å
- ã¤ã³ãµã¼ãç´åã§ActiveRecord::Base.clear_active_connections!ãå¼ã¶ã¨ç´ãã¨æãã¾ãã
Railsã§ãªã¯ã¨ã¹ãã®ãã³ã«åæ¥ç¶ãããé¨åã®ã½ã¼ã¹ãã£ãã
railsåæåæã«ãªã¯ã¨ã¹ãæ¯ã«å®è¡ãããrackã®ããã«ã¦ã§ã¢ã¨ãã¦ActiveRecord::ConnectionAdapters::ConnectionManagementã追å ãã¦ããã
ConnectionManagementã®ä¸ã§ã¯ActiveRecord::Base.clear_active_connections!ãå¼ã°ããã®ã§ã³ãã¯ã·ã§ã³ãåæ¥ç¶ãã¦ããããã
# rails-2.3.8\lib\initializer.rb def initialize_database_middleware if configuration.frameworks.include?(:active_record) if configuration.frameworks.include?(:action_controller) && ActionController::Base.session_store.name == 'ActiveRecord::SessionStore' configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::QueryCache else configuration.middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement configuration.middleware.use ActiveRecord::QueryCache end end end
# activerecord-2.3.8\lib\active_record\connection_adapters\abstract\connection_pool.rb class ConnectionManagement def initialize(app) @app = app end def call(env) @app.call(env) ensure # Don't return connection (and peform implicit rollback) if # this request is a part of integration test unless env.key?("rack.test") ActiveRecord::Base.clear_active_connections! end end end
ActiveRecord::Base.clear_active_connections!ãå¼ã°ããã¨ã³ãã¯ã·ã§ã³ãã³ãã¯ã·ã§ã³ãã¼ã«ã«è¿å´(checkin)ãããã
ã³ãã¯ã·ã§ã³èªä½ã¯ãã¼ã«ããã¦ã¦æ¥ç¶ã¯ç¶æãããã¾ã¾ã§ãããããã¾ã§ç¾ã¹ã¬ããã§ä½¿ããã¼ã«ããããã£ã¦ãã³ãã¯ã·ã§ã³ããã§ãã¯ã¤ã³ããã ãããããã³ãã¯ã·ã§ã³ãã¼ãªã³ã°ã£ã¦ããã ã
# activerecord-2.3.8\lib\active_record\connection_adapters\abstract\connection_pool.rb def clear_active_connections! @connection_pools.each_value {|pool| pool.release_connection } end def release_connection conn = @reserved_connections.delete(current_connection_id) checkin conn if conn end
ããããªãã§ã³ãã¯ã·ã§ã³ãã¼ãªã³ã°ã«è¿å´ãããã¨åæ¥ç¶ããããã¨ããã¨
ã³ãã¯ã·ã§ã³ãã¼ãªã³ã°ããæ¥ç¶ããããé(checkout)ã«åæ¥ç¶ããããããã§ããã
def connection if conn = @reserved_connections[current_connection_id] conn else @reserved_connections[current_connection_id] = checkout end end
ï¼å°ãè±ç·ï¼ã¡ãªã¿ã«@reserved_connectionsã¯ãã§ãã¯ã¢ã¦ãããã³ãã¯ã·ã§ã³ããã£ãã·ã¥ãã¦ããhashã£ã½ããcurrent_connection_idã¯ThreadIDã¿ãããªãã®ãªã®ã§ã¹ã¬ãããã¨ã«æ¥ç¶ãã¯ããã¦ãã£ãã·ã¥ãããä»çµã¿ï¼ãã«ãã¹ã¬ãã対å¿ã®ããï¼ãï¼
def current_connection_id #:nodoc: Thread.current.object_id end
ã¡ããçç¥ãããcheckoutã辿ã£ã¦ãã¨checkout_and_verifyãå¼ã°ãããããã§ã³ãã¯ã·ã§ã³ã«å¯¾ãã¦verifyãå¼ã°ããã
def checkout_and_verify(c) c.verify! c.run_callbacks :checkout @checked_out << c c end
verifyã®ä¸ã§active?ãå¼ãã§æ¥ç¶ããã¦ãããã確èªããåãã¦ãå ´åã¯reconnectãã¦ããã
# activerecord-2.3.8\lib\active_record\connection_adapters\abstract_adapter.rb def verify!(*ignored) reconnect! unless active? end
ãªãabstract_adapter.rbã§å®ç¾©ããã¦ãactive?ã¯
def active? @active != false end def disconnect! @active = false end
ã¨ãããã¼ããªãã®ã ã
mysql_adapterã§ãã¡ãã¨å®è£ ãããªããã¦ããã
# activerecord-2.3.8\lib\active_record\connection_adapters\mysql_adapter.rb def active? if @connection.respond_to?(:stat) @connection.stat else @connection.query 'select 1' end # mysql-ruby doesn't raise an exception when stat fails. if @connection.respond_to?(:errno) @connection.errno.zero? else true end rescue Mysql::Error false end