Steps to reproduce
- Create one
Fbe::Middleware::SqliteStore and configure it as the Faraday HTTP cache store.
- Share the client across two threads that make cacheable requests at the same time, so both threads call
read or write on the store.
- Repeat the requests while the cache is enabled.
Actual result
perform protects only the lazy initialization of @db; it calls @db.transaction(&) after releasing the mutex. Two overlapping store operations can therefore start transactions on the same SQLite connection. The sqlite3 Ruby API documents that nested transactions are not allowed, so an overlapping operation can raise a SQLite exception and make the corresponding Faraday request fail.
Expected result
The store should serialize each complete transaction on the shared connection, or use separate connections, so concurrent cache operations do not start nested transactions or fail requests.
Technical evidence
lib/fbe/middleware/sqlite_store.rb:189-197 locks only @db ||= open!, then invokes @db.transaction(&) outside the lock. read, write, delete, clear, and all all use perform, so their transactions can overlap. lib/fbe/octo.rb:108-119 installs this store into the Faraday cache middleware used by the GitHub client. The sqlite3 dependency is ~> 2.6; its transaction implementation and documentation state that nested transactions raise at runtime.
Steps to reproduce
Fbe::Middleware::SqliteStoreand configure it as the Faraday HTTP cache store.readorwriteon the store.Actual result
performprotects only the lazy initialization of@db; it calls@db.transaction(&)after releasing the mutex. Two overlapping store operations can therefore start transactions on the same SQLite connection. The sqlite3 Ruby API documents that nested transactions are not allowed, so an overlapping operation can raise a SQLite exception and make the corresponding Faraday request fail.Expected result
The store should serialize each complete transaction on the shared connection, or use separate connections, so concurrent cache operations do not start nested transactions or fail requests.
Technical evidence
lib/fbe/middleware/sqlite_store.rb:189-197locks only@db ||= open!, then invokes@db.transaction(&)outside the lock.read,write,delete,clear, andallall useperform, so their transactions can overlap.lib/fbe/octo.rb:108-119installs this store into the Faraday cache middleware used by the GitHub client. The sqlite3 dependency is~> 2.6; its transaction implementation and documentation state that nested transactions raise at runtime.