These are chat archives for AlgoLab/pinw

18th
Nov 2014
Loris Cro
@kappaloris
Nov 18 2014 17:42
This message was deleted
Loris Cro
@kappaloris
Nov 18 2014 19:49

Dunque ho avuto un problema serio con activerecord ed sqlite3.
Sostanzialmente il cron lancia subito un po’ di processi che cercano di contendersi il database ma per qualche motivo capitano due cose su cui non ho un controllo diretto:

  1. ActiveRecord apre una transazione per ogni query di scrittura, ad esempio:

    D, [2014-11-18T18:36:44.591697 #4076] DEBUG -- :    (0.1ms)  begin transaction
    D, [2014-11-18T18:36:44.592735 #4076] DEBUG -- :   SQL (0.2ms)  UPDATE "processing_status" SET "updated_at" = ?, "value" = ? WHERE "processing_status"."key" = 'FETCH_CRON_LOCK'  [["updated_at", "2014-11-18 17:36:44.591959"], ["value", "--- 4076\n...\n"]]
    D, [2014-11-18T18:36:44.594396 #4076] DEBUG -- :    (1.5ms)  commit transaction

    Scrivendo un po’ su #rubyonrails@freenet mi hanno notare che non si tratta di pessima implementazione, ma di una scelta di design: ultimamente va di moda che gli ORM offrano dei hook pre commit che permettano anche di fare il rollback delle transazioni sulla base di logiche “buttate” altrove. In questo modo modelli diversi possono “comunicare” senza che siano espressamente progettati per farlo (ad esempio author.delete viene annullato tramite pre-commit book da Book perche’ book contiene la regola che ogni libro deve avere un autore presente (secondo la filosofia di rails&co tutte queste logiche dovrebbero stare nell’applicazione non nel DBMS)).

  2. Quando un altro processo cerca di prendere il possesso del db e lo trova lockato istantaneamente solleva una eccezione (SQLite3::BusyException). Il metodo che dovrebbe permettere di alzare questo timeout sembra non funzionare. In particolare sarebbe l’opzione :timeout espressa in millisecondi che viene passata assieme al nome del db all’atto della connessione. Quel timeout si riferisce correttamente al timeout di attesa dei lock (lo si vede qui: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L31 ) ma, come dicevo, ad alzarlo non cambia nulla.

Ho provato a disabilitare le transazioni completamente con un po’ di sano monkey patching:

module SqliteTransactionFix
  def begin_db_transaction
    log('transaction prevented', nil){}
  end

  def commit_db_transaction
    log('commit prevented', nil){}
  end
end

module ActiveRecord
  module ConnectionAdapters
    class SQLite3Adapter < AbstractAdapter
      prepend SqliteTransactionFix
    end
  end
end

Su OSX continua a dare problemi: SQLite3::IOException: disk I/O error: ma su Linux mi pare andasse (l’ho fatto provare a Luca De Sano che pero’ al momento e’ altrove e quindi non posso confermare). Nel caso rimarrebbe il problema che tutte le transazioni sono disabilitate a meno di mettere mano a parti di activerecord che non dovrebbero essere propriamente pubbliche.

Per testare questa cosa: da una installazione funzionante (ed aggiornata) di pinw incollate la copia del database che vi passo sotto al posto del vostro e dalla cartella di pinw invocate

ruby cron/pinw-fetch.rb

Link al database contenente un po’ di lavori da processare: https://www.dropbox.com/s/b4nb2iyms9ow9k7/pinw.db?dl=0

(metto un link perche’ il form di creazione dei job funziona ma ha ancora qualche bug ed in questo modo si fa prima a fare piu’ di un test)

Loris Cro
@kappaloris
Nov 18 2014 19:59
Aggiorno: ho appena provato con una macchina virtuale (ubuntu14.04 + ruby 2.1) e non ha dato problemi. Non so cosa faccia di brutto osx per causare gli altri errori.
(ho notato che nel messaggio grosso ci sono un paio di typo dovuti al simpatico autocorrettore di osx che adora autoabilitarsi, spero si capisca lo stesso)