This is a pretty common error, but for me, the problem isn’t going away. When I run rake db:{drop,create,migrate,seed}
or rake db:seed
ActiveRecord raises:
#<ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked>
The fault is my seeds.rb:
require 'etc'
NAME = (?a..?y).to_a.permutation
ITEMS = 200
PROCESSORS = Etc.nprocessors * 2
FORK_PIDS = []
time = Time.now
ITEMS.times do |i|
elap = Time.now - time
est_rem = ITEMS.*(elap)./(i).-(elap).round(2)
print "\e[2K#{i}/#{ITEMS} | Elapsed #{elap.round(2)}s | Rem #{est_rem}s \r"
if FORK_PIDS.length > PROCESSORS
Process.wait(FORK_PIDS.shift)
redo
else
name = NAME.next.join.capitalize
FORK_PIDS << Process.fork { User.create!(username: name, password: 'randomuser') rescue (p $!) }
end
end
FORK_PIDS.each(&Process.method(:wait))
I used to run this code fine, but now it’s not working even once.
My database.yml looks like this:
default: &default
adapter: sqlite3
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
development:
<<: *default
database: db/development.sqlite3
timeout: 30000
test:
<<: *default
database: db/test.sqlite3
production:
<<: *default
database: db/production.sqlite3
So in development mode, the timeout is set to 30s. But the insertion doesn’t wait for a couple of seconds. If I seed 200 entries, I get the error 5 - 6 times.
The issue can be solved by wrapping the code inside fork in a begin rescue block:
FORK_PIDS << Process.fork do
begin
User.create!(username: name, password: 'randomuser')
rescue Exception
sleep 0.01
retry
end
end
This works fine, but I am not sure if it’s a good practice…
What’s the way to get around this problem? I know it’s the issue of fork, but I want to keep fork and set timeout for the database. How do I do that?