12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

seeds.rbなどでActiveStorageを使って大量の画像をアップロードする際に発生する SQLite3::BusyException の対処法

Posted at

発生する問題

Railsのrails db:seedを実行すると、以下のようなエラーが起きる場合がある。

$ rails db:seed
rails aborted!
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked
/path-to-your-app/db/seeds.rb:69:in `<main>'

エラーが発生するコード例

エラーが発生した周辺のコードは次のようになっている。

# ...

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')
  # ActiveStorageを使ってavatarを設定
  user.avatar.attach(io: URI.parse(image_url).open, filename: 'avatar.png')
end

# ...

加えて、このアプリケーションではSQLite3を使っている。

default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3

エラーが発生する原因

このエラーは以下の2つの要因で引き起こされる。

  • ActiveStorageを使っているため、画像のアップロードや削除が非同期で行われる
  • SQLite3は並行処理に弱い(参考

User.destroy_allをしたときは既存のデータに対して画像の削除処理が非同期で実行される。既存のデータが大量にあると、データベースに対して読み込みや書き込みのクエリが並行して発行される。

user.avatar.attachも同様に非同期で画像のアップロード処理が行われる。上のコード例では100件のユーザーデータを作成しようとしたため、やはりデータベースに対して読み込みや書き込みのクエリが並行して発行される。

SQLiter3が並行処理に耐えきれなくなると、SQLite3::BusyExceptionが発生する。

エラー回避策

SQLite3の性能上の制約を考慮し、画像の削除処理やアップロード処理を同期的に行うようにする。具体的には以下の2行を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はアップロード時に、ActiveStorage::PurgeJobは削除時にそれぞれ利用されるActiveJobのクラスである。
このqueue_adapter:inlineに変更することで、画像のアップロードや削除を同期的に実行できる。

参考 https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html

動作確認環境

  • Rails 6.1.0
  • Ruby 3.0.0
  • SQLite3 3.32.3
12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?