The default timeout for a sqlite3 database is 5 seconds.
When a model uses validates_uniqueness_of, it does not honor this timeout.
It throws a SQLite3::BusyException immediately.
I have a model:
class TestLock < ActiveRecord::Base
validates_uniqueness_of :name
end
with a migration like this:
class CreateTestLocks < ActiveRecord::Migration
def self.up
create_table :test_locks do |t|
t.column :name, :string
end
end
end
and I'm using the default sqlite3 database.yml:
development:
adapter: sqlite3
database: db/development.sqlite3
timeout: 5000
If I migrate then lock the database in one terminal like this:
$ sqlite3 development.sqlite3
SQLite version 3.3.17
Enter ".help" for instructions
sqlite> begin immediate;
Then, in a different terminal:
$ script/console
Loading development environment.
>> tl = TestLock.new
=> #<TestLock:0x25350f0 @attributes={"name"=>nil}, @new_record=true>
>> tl.name = "foobar"
=> "foobar"
>> tl.save
The save call immediately triggers an exception:
ActiveRecord::StatementInvalid: SQLite3::BusyException: \
database is locked: INSERT INTO test_locks ("name") VALUES('foobar')
If I then comment out the validates_uniqueness_of from the model:
class TestLock < ActiveRecord::Base
#validates_uniqueness_of :name
end
And retry the test, the save call waits the appropriate 5 seconds before throwing the SQLite3::BusyException.
And if I do the test, but release the lock from the first terminal within 5 seconds:
sqlite> rollback;
the transaction succeeds:
>> tl.save
=> true
I'm running on:
rails (1.2.3)
activerecord (1.15.3)
sqlite3-ruby (1.2.1)
SQLite version 3.3.17