2009-10-08 3 views
12

Je rencontre quelques erreurs sur une application de rails, le long des lignes de:Dans quelles circonstances vous voulez Rails à régler pas se reconnecter à MYSQL

ActiveRecord::StatementInvalid: Mysql::Error: Lost connection to MySQL server during query: SELECT * FROM `actions` WHERE (`foo`.`id` = 16) 

Ce qui semble se produire est que MySQL la connexion est fermée après un délai d'expiration et les rails ne remarquent pas jusqu'à ce qu'il soit trop tard.

Le remedies I findappear to be pour définir le drapeau de rebranchement à true dans database.yaml, ou pour toute action de base de données en ajoutant quelques code comme ceci:

def some_database_operation 
    begin 
    Account.find(1) 
    # or some other database operations here... 
    rescue ActiveRecord::StatementInvalid 
    ActiveRecord::Base.connection.reconnect! 
    unless @already_retried 
     @already_retried = true 
     retry 
    end 
    raise 
    else 
    @already_retried = false 
    end 
end 
end 

Je liste cette option over this one visible here, parce que cette option est apparemment peu sûr pour les transactions:

ActiveRecord::ConnectionAdapters::MysqlAdapter.module_eval do 
    def execute_with_retry_once(sql, name = nil) 
    retried = false 
    begin 
     execute_without_retry_once(sql, name) 
    rescue ActiveRecord::StatementInvalid => exception 
     ActiveRecord::Base.logger.info "#{exception}, retried? #{retried}" 

     # Our database connection has gone away, reconnect and retry this method 
     reconnect! 
     unless retried 
     retried = true 
     retry 
     end 
    end 
    end 

    alias_method_chain :execute, :retry_once 
end 

Parmi les options pour éviter cette erreur ennuyeux, l'option de rebranchement dans le fichier YAML semble par l'extrême l'option tidiest - mais je suis curieux; Pourquoi ne pas définir cette valeur par défaut dans votre base de données?

Je préfère ne pas résoudre un problème en causant une charge d'autres plus bas sur la ligne.

Merci,

Répondre

12

Comme vous l'avez indiqué dans la question, un effet secondaire possible de se reconnecter automatiquement (si elle est faite à un niveau par-déclaration), est que ce n'est pas transactionnelles.

Le MySQL documentation en fait indique explicitement que la fonction auto-Reconnect affecte les transactions:

Toutes les transactions actives sont annulées et le mode de validation automatique est remis à zéro.

Les applications qui ne sont pas écrites pour traiter cela pourraient facilement se casser. La documentation répertorie également un certain nombre d'autres effets secondaires causés par la fonctionnalité de reconnexion automatique, qui peuvent tous entraîner des applications non écrites à anticiper le comportement de fonctionner de manière incorrecte ou échouer.

En outre, si la connexion à la base de données est soudainement perdu, le serveur peut-être pas correctement libérer les verrous qui étaient détenus par la connexion, il sonne comme une application peut se bloquer dans certains cas:

Si la connexion tombe, il est possible que la session associée à la connexion côté serveur soit toujours en cours d'exécution si le serveur n'a pas encore détecté que le client n'est plus connecté. Dans ce cas, tous les verrous détenus par la connexion d'origine appartiennent toujours à cette session , donc vous pouvez vouloir le tuer par en appelant mysql_kill().

+2

Ok maintenant je suis totalement confus. Cela me suggère que la définition de 'reconnexion 'à' vrai' pourrait être nuisible, parce que les transactions qui sont annulées lorsqu'elles ne sont pas supposées sont une mauvaise chose. Quelle est la solution de contournement habituelle pour éviter cet état de choses? –

+0

La solution consiste à s'assurer que vos transactions sont «atomiques», c'est-à-dire que si vous perdez la connexion et que vous vous reconnectez, toute la transaction doit être réessayée, pas seulement une seule déclaration dans la transaction. Je ne suis pas sûr comment cela fonctionne dans Rails, mais je suppose qu'une solution serait de mettre la transaction dans une procédure stockée - dans le code Rails, vous exécutez une seule instruction SQL pour exécuter la procédure stockée, puis si elle se reconnecte automatiquement , toute la transaction recommence depuis le début. –

+0

OTOH, si vous n'utilisez pas de transactions, l'utilisation de la fonctionnalité de reconnexion automatique est probablement moins problématique. –

5

De la Rails 2.3 release notes (Souligné par l'auteur): - si elle est définie sur true, le

4.8 Reconnexion Connexions MySQL

MySQL prend en charge un drapeau de rebranchement dans ses connexions le client essaiera de se reconnecter au serveur avant de renoncer en cas de perte de connexion. Vous pouvez maintenant définir reconnect = true pour vos connexions MySQL dans database.yml pour obtenir ce comportement à partir d'une application Rails. La valeur par défaut est false, afin que le comportement des applications existantes ne change pas.

Questions connexes