When running Rails rails db: seed
, the following error may occur.
$ rails db:seed
rails aborted!
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked
/path-to-your-app/db/seeds.rb:69:in `<main>'
The code around the error is as follows.
# ...
User.destroy_all
100.times do |n|
user = User.create!(
email: "sample-#{n}@example.com",
password: 'password',
name: Faker::Name.name
)
image_url = Faker::Avatar.image(slug: user.email, size: '150x150')
#Set up avatar using Active Storage
user.avatar.attach(io: URI.parse(image_url).open, filename: 'avatar.png')
end
# ...
In addition, this application uses SQLite3.
default: &default
adapter: sqlite3
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
development:
<<: *default
database: db/development.sqlite3
This error is caused by two factors:
--Since ActiveStorage is used, images are uploaded and deleted asynchronously. --SQLite3 is vulnerable to concurrency (Reference)
When User.destroy_all
is executed, the image deletion process is executed asynchronously for the existing data. If you have a large amount of existing data, read and write queries will be issued to the database in parallel.
Similarly, user.avatar.attach
also performs image upload processing asynchronously. In the above code example, we tried to create 100 user data, so read and write queries are also issued to the database in parallel.
SQLite3 :: BusyException occurs when SQLiter3 cannot withstand concurrency.
Considering the performance restrictions of SQLite3, delete and upload images should be performed synchronously. Specifically, add the following two lines to config/seeds.rb
.
+ActiveStorage::AnalyzeJob.queue_adapter = :inline
+ActiveStorage::PurgeJob.queue_adapter = :inline
User.destroy_all
100.times do |n|
user = User.create!(
email: "sample-#{n}@example.com",
password: 'password',
name: Faker::Name.name
)
image_url = Faker::Avatar.image(slug: user.email, size: '150x150')
user.avatar.attach(io: URI.parse(image_url).open, filename: 'avatar.png')
end
ActiveStorage :: AnalyzeJob is a class of ActiveJob used at the time of upload and ActiveStorage :: PurgeJob is used at the time of deletion.
By changing this queue_adapter
to: inline
, you can upload and delete images synchronously.
Reference https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html
Recommended Posts