Thursday, March 1, 2018

Table name corruption errors in ActiveRecord

Leave a Comment

Sporadically we get PG::UndefinedTable errors while using ActiveRecord. The association table name is some how corrupted and I quite often see Cancelled appended to the end of the table name.

E.g:

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "fooCancell" does not exist  ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "Cancelled" does not exist ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "barC" does not exist 

In the example above, I have obfuscated the table name by using foo and bar.

We see this errors when the rails project is running inside Puma. Queue workers seems to be doing okay.

The tables in the error message doesn't correspond to real tables or models. It looks like the case of memory corruption. Has anyone seen such issues? If so how did you get around it?

puma.rb

on_worker_boot do   ActiveRecord::Base.establish_connection end 

database.yml

production:   url:  <%= ENV["DATABASE_URL"] %>   pool: <%= ENV['DB_CONNECTION_POOL_SIZE'] || 5%>   reaping_frequency: <%= ENV['DB_CONNECTION_REAPING_FREQUENCY'] || 10 %>   prepared_statements: false 

2 Answers

Answers 1

It looks like reaping_frequency may be the issue. I found a couple claims that they may have a threading bug. I would try removing that option or setting it to nil and see if that works. The only other thing I can think of is if you are manually calling Thread.new and using active record within it. Here are the few claims against reaping:

http://omegadelta.net/2014/03/15/the-rails-grim-reaper/

https://github.com/mperham/sidekiq/issues/1936

Search for "DO fear the Reaper" here: https://www.google.com/amp/s/bibwild.wordpress.com/2014/07/17/activerecord-concurrency-in-rails4-avoid-leaked-connections/amp/

Answers 2

I'm hazarding a guess here...

But you might be either:

  1. calling fork within your application; OR
  2. calling ActiveRecord routines (using database calls) before the server (puma) is forking it's worker processes (during the app initialization).

Either of these will break ActiveRecord's synchronization and cause multiple processes to share the database connection pool without synchronizing it's use (resulting in interlaced and corrupt database commands).

If you are using fork, make sure to close all the ActiveRecord database connections and reinitialize the connection pool (there's a function call that does it, but I don't remember it of the top of my head, maybe ActiveRecord.disconnect! or ActiveRecord.connection_pool.disconnect!).

Otherwise, before running Puma (either during the initialization process or using Puma's at_fork), close all the ActiveRecord database connections and reinitialize the connection pool.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment