baash05
baash05

Reputation: 4516

rails activerecord transaction blocks don't seem to not commit

I've a rails app that I'm crashing on purpose.. it's local and I'm just hitting ctrl + c and killing it mid way through processing records..

To my mind the records in the block shouldn't have been committed.. Is this a postgres "error" or a rails "error", or a dave ERROR?

      ActiveRecord::Base.transaction do
        UploadStage.where("id in (#{ids.join(',')})").update_all(:status => 2);

        records.each do |record|
          record.success = process_line(record.id, klas, record.hash_value).to_s[0..250]
          record.status = 1000
          record.save();
        end    
      end

I generate my ids by reading out all the records where the status is 1.
Nothing but this function sets the status to 1000..

If the action crashes for what ever reason, I'd expect there to be no records in the database with status = 2... This is not what I'm seeing though. Half the records have status 1000, the other half have status 2.. .

Am I missing something?
How can I make sure there are no 2's if the app crashes?


EDIT:
I found this link http://coderrr.wordpress.com/2011/05/03/beware-of-threadkill-or-your-activerecord-transactions-are-in-danger-of-being-partially-committed/

Upvotes: 3

Views: 2004

Answers (1)

Craig Ringer
Craig Ringer

Reputation: 324465

As I suspected and as confirmed by dave's update, it looks like ActiveRecord will commit a half-finished transaction under some circumstances when you kill a thread. Woo, safe! See dave's link for detailed explanation and mitigation options.

If you're simulating hard crash (host OS crash or plug-pull), control-C is absolutely not the right approach. Use Control-\ to send a SIGQUIT, which is generally not handled, or use kill -KILL to hard-kill the process with no opportunity to do cleanup. Control-C sends SIGINT which is a gentle signal that's usually attached to a clean shutdown handler.

In general, if you're debugging issues like this, you should enable detailed query logging and see what Rails is doing. Use log_statement = 'all' in postgresql.conf then examine the PostgreSQL logs.

Upvotes: 1

Related Questions