2013-07-27 3 views
7

Sto provando a utilizzare l'alembic con un motore MySQL per eseguire migrazioni online. Ho scoperto che quando un'operazione nel mio metodo onupgrade() fallisce il mio database si blocca in uno stato incoerente e non posso usare l'alambicco finché non pulisco manualmente tutte le operazioni avvenute prima dell'errore in onupgrade()come pulire il ciclo alambicco incompleto

esempio:

def upgrade(): 
    op.create_table('sometable', 
      Column('id', INTEGER, primary_key=True), 
      Column('name', VARCHAR(150), nullable=False, unique=True)) 
    op.add_column('anothertable' Column('id', INTEGER)) 
    op.create_table('secondtable') 

quindi, se corro questo e l'op.add_column fallisce, anche se posso correggere la linea add_column, ora "SomeTable" esiste quindi la prima operazione fallirà sempre. Non riesco a eseguire il mio script di downgrade, perché alembic non ha mai aggiornato la versione poiché non ha completato l'aggiornamento.

Stavo pensando se c'era un modo per forzare l'esecuzione del mio ondowngrade(), che potrebbe essere utile. Dovrei ignorare gli errori, perché ce ne saranno sicuramente. Come far cadere "secondtable". Tuttavia non sono riuscito a trovare comunque questo.

Qualcuno ha un buon modo per gestire questo?

+1

Solo un'ipotesi: sospetto che il alembic provi a eseguire le migrazioni in una transazione e ripristini gli errori - ma probabilmente la tua configurazione MySQL non supporta le transazioni, quindi tu Sei sfortunato. – moschlar

+1

Questo è quello che temevo, MySQL non supporta le transazioni per le istruzioni DDL :(http://dev.mysql.com/doc/refman/5.0/en/cannot-roll-back.html – jjulien

risposta

6

Il problema non riguarda l'alambicco, ma l'utilizzo di MySQL, che non può eseguire il rollback delle istruzioni DDL.

Quindi l'unico (brutto) modo per ottenerlo sarebbe quello di eseguire la gestione manuale delle eccezioni e invertire le operazioni che hanno avuto successo fino a quel momento.

Qualcosa di simile (scritto fuori dalla mia mente, quindi non è la soluzione più elegante e forse anche un po 'sbagliato, ma spero che si ottiene il succo):

def upgrade(): 
    try: 
     op.create_table('sometable', 
      Column('id', INTEGER, primary_key=True), 
      Column('name', VARCHAR(150), nullable=False, unique=True)) 
    except: 
     try: 
      op.drop_table('sometable') 
     except: 
      pass 
     raise 

    try: 
     op.add_column('anothertable' Column('id', INTEGER)) 
    except: 
     op.drop_table('sometable') 
     try: 
      op.drop_column('anothertable', 'id') 
     except: 
      pass 
     raise 

    try: 
     op.create_table('secondtable') 
    except: 
     op.drop_table('sometable') 
     op.drop_column('anothertable', 'id') 
     try: 
      op.drop_table('secondtable') 
     except: 
      pass 
     raise 
0

Se avete in controllo di versione dal modello di database da cui si sta migrando, è possibile utilizzarlo temporaneamente per creare una migrazione. (Potrebbe essere necessario svuotare la cartella delle versioni/inserire tutto in una directory temporanea) Alembic confronterà lo stato corrente del database con il modello e fornirà i comandi di migrazione per il database per raggiungere tale stato. In questo caso, dovrebbe darti le istruzioni per riportare il database allo stato precedente. Dovrai esaminare i comandi di migrazione che sono stati generati per assicurarti che sia esattamente ciò di cui hai bisogno, ma non dovrai generarli tu stesso.

Successivamente è possibile eliminare la migrazione e tornare all'ultima versione del file modello db. Quindi dovresti tornare al punto in cui hai iniziato