Replies: 11 comments 5 replies
-
There are a few built-in options for busy handlers
@fractaledmind has written a few blog posts on this topic, e.g. https://fractaledmind.github.io/2024/01/11/sqlite-in-ruby-non-blocking-timeout/ if that's interesting. |
Beta Was this translation helpful? Give feedback.
-
@flavorjones: Thanks for reaching out and pointing to available options. Some followup-questions:
SQLite3::Database.open('db', busy_handler: lambda { |e| puts e; sleep 1; true })
SQLite3::Database.open('db', busy_timeout: 1000)
SQLite3::Database.open('db', busy_handler_timeout: 1000)
|
Beta Was this translation helpful? Give feedback.
-
@flavorjones: Still need a hand here. Puzzled why running two simple connections to the same db breaks so easily. |
Beta Was this translation helpful? Give feedback.
-
I can't reproduce what you're describing in your OP. I'm using sqlite3 v2.0.2 (precompiled x86_64-linux-gnu) on linux and |
Beta Was this translation helpful? Give feedback.
-
Thanks for confirming. Will try to pinpoint the issue. |
Beta Was this translation helpful? Give feedback.
-
@flavorjones: Can you reproduce this? (I'm on macOS 14.5) $ sqlite3 hello
sqlite> create table foo (bar);
sqlite> insert into foo values (1); irb(main):001> db = SQLite3::Database::open('hello', busy_timeout: 1000)
irb(main):002> db.query('select * from foo where bar = ?', [1]).any?
=> true Another shell: irb(main):001> db = SQLite3::Database::open('hello', busy_timeout: 1000)
irb(main):002> db.query('insert into foo values (?)', [1])
/opt/homebrew/lib/ruby/gems/3.3.0/gems/sqlite3-2.0.2-arm64-darwin/lib/sqlite3/statement.rb:84:in `step': database is locked (SQLite3::BusyException) |
Beta Was this translation helpful? Give feedback.
-
Yes, I can reproduce that. Setting journal mode to WAL will allow you to have reads concurrent with writes. See @fractaledmind's excellent blog post on configuring SQLite3 for concurrent access here: https://fractaledmind.github.io/2023/09/07/enhancing-rails-sqlite-fine-tuning/ And the SQLite docs themselves: https://www.sqlite.org/pragma.html#pragma_locking_mode |
Beta Was this translation helpful? Give feedback.
-
OK, this is actually quite simple. Assuming what happens:
Now, collision does not occur if removing Questions:
|
Beta Was this translation helpful? Give feedback.
-
@flavorjones: I really appreciate this clarification. You're right. One assumes a project maintainer is God and knows everything. I'll take this incident as a reminder that this might -- and should necessarily -- not be the case. |
Beta Was this translation helpful? Give feedback.
-
@fractaledmind: Could you reply to the posting above ("OK, this is actually quite simple...") |
Beta Was this translation helpful? Give feedback.
-
@flavorjones + @fractaledmind + @oldmoe: OK, the solution is actually quite obvious. If a ResultSet is not going to be iterated, it must be closed, lest the database is locked forever waiting for iteration that never comes. If one never does iteration after refine SQLite3::ResultSet do
def any?
super.tap(&:close)
end
end Could the API be changed or extended in accordance? Note: Updated code example to return the object as expected |
Beta Was this translation helpful? Give feedback.
-
Referring to #261, etc. is
SQLite3::BusyException
warranted and unavoidable, even if hitting up the database from two different processes, as opposed to two threads in the same process?sqlite> create table foo (bar);
Is there no way around everyone having to write their own busy handler?
Or use Write-Ahead Logging?
Beta Was this translation helpful? Give feedback.
All reactions