2009-10-08 13 views
12

sto sperimentando alcuni errori su un app rotaie, lungo le linee di:In quali circostanze si vorrebbe Rails da impostare non riconnettersi al MYSQL

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

Quello che sembra accadere è che mysql la connessione viene chiusa dopo un timeout e le guide non si accorgono fino a quando non è troppo tardi.

La remedies I findappear to be per impostare il flag riconnessione al vero in database.yaml, o per qualsiasi azione di database aggiungendo un po 'di codice in questo modo:

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 

sto messa in vendita di questa opzione over this one visible here, perché questa opzione è apparentemente non sicuro per le transazioni:

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 

Tra le opzioni per evitare questo errore fastidioso, l'opzione di riconnessione nel file YAML sembra di gran lunga l'opzione più ordinata - ma sono curioso; perché non dovresti impostare questo valore come vero per impostazione predefinita nel tuo database?

Preferisco non risolvere un problema causando un carico di altri più in basso.

Grazie,

risposta

12

Come lei ha sottolineato nella questione, una possibile effetto collaterale di riconnettersi automaticamente (se fatto ad un livello per-economico), è che non è transaction-safe.

MySQL documentation infatti afferma esplicitamente che la funzione di auto-riconnessione colpisce le transazioni:

eventuali transazioni attive vengono annullate e modalità autocommit è reset.

Le applicazioni che non sono state scritte per risolvere questo problema potrebbero facilmente interrompersi. La documentazione elenca anche una serie di altri effetti collaterali causati dalla funzione di riconnessione automatica, ognuno dei quali potrebbe far sì che le applicazioni non siano scritte per anticipare il comportamento in modo errato o non riuscire.

Inoltre, se la connessione al database è improvvisamente perso, il server potrebbe non rilasciare correttamente blocchi che sono stati detenuti dal collegamento, in modo che suona come un applicazione potrebbe stallo in alcuni casi:

Se la connessione si interrompe, è possibile che la sessione associata con la connessione sul lato server sia ancora in esecuzione se il server non ha ancora rilevato che il client non è più connesso. In questo caso, tutti i blocchi trattenuti dalla connessione originale appartengono ancora a quella sessione , quindi potresti volerli uccidere tramite chiamando mysql_kill().

+2

Ok ora sono totalmente confuso. Questo mi suggerisce che impostare 'reconnect' su' true' potrebbe essere dannoso, perché le transazioni che vengono annullate quando non vengono considerate sembrano una cosa negativa. Qual è la solita soluzione alternativa per evitare questo stato di cose? –

+0

La soluzione è assicurarsi che le transazioni siano "atomiche", ovvero se si perde la connessione e si riconnette, l'intera transazione deve essere ripetuta, non solo una singola istruzione all'interno della transazione. Non sono sicuro di come funzioni in Rails, ma credo che una soluzione sarebbe quella di mettere la transazione in una stored procedure - nel codice Rails, si esegue una singola istruzione SQL per eseguire la stored procedure, quindi se si riconnette automaticamente , l'intera transazione ricomincia dall'inizio. –

+0

OTOH, se non si stanno utilizzando le transazioni, quindi utilizzare la funzione di riconnessione automatica è probabilmente meno di un problema. –

5

Dal Rails 2.3 release notes (sottolineatura mia):

4.8 Ricollegamento connessioni MySQL

MySQL supporta una bandiera riconnessione nelle sue connessioni - se impostato su true, allora la il client proverà a riconnettersi al server prima di rinunciare in caso di connessione persa. È ora possibile impostare reconnect = true per le connessioni MySQL in database.yml per ottenere questo comportamento da un'applicazione Rails. L'impostazione predefinita è false, , pertanto il comportamento delle applicazioni esistenti non cambia.

Problemi correlati