Skip to content

SqliteStore does not serialize transactions shared by concurrent threads #1342

Description

@gemshrine

Steps to reproduce

  1. Create one Fbe::Middleware::SqliteStore and configure it as the Faraday HTTP cache store.
  2. Share the client across two threads that make cacheable requests at the same time, so both threads call read or write on the store.
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions