mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 15:05:24 +08:00
836ab73d59
A single SchemaCache instance is maintained by the connection pool, and made available via a schema_cache method on each connection. When the SchemaCache instance is fetched from the pool, its internal connection reference is updated to equal the requesting connection. However, since there is only one instance of SchemaCache, this internal connection reference is updated everywhere, and can ultimately result in multiple threads accessing the same database connection. In Discourse, this could result in Sidekiq jobs getting 'stuck' in database connections. This patch modifies SchemaCache so that it caches the internal connection on a per-thread basis Co-authored-by: Sam Saffron <sam.saffron@gmail.com> Co-authored-by: Matt Palmer <mpalmer@hezmatt.org>
28 lines
800 B
Ruby
28 lines
800 B
Ruby
# frozen_string_literal: true
|
|
#
|
|
# Rails has a circular dependency in SchemaCache.
|
|
# In certain situation SchemaCache can carry a @connection
|
|
# from a different thread. This causes potential concurrency bugs
|
|
# in Sidekiq.
|
|
#
|
|
# This patches it so it is less flexible (theoretically) but always bound to the current connection
|
|
|
|
# This patch needs to be reviewed in future versions of Rails.
|
|
# We should consider upstreaming this optionally.
|
|
|
|
module ActiveRecord
|
|
module ConnectionAdapters
|
|
class SchemaCache
|
|
|
|
def connection=(connection)
|
|
# AbstractPool get_schema_cache does schema_cache.connection = connection
|
|
Thread.current["schema_cached_connection"] = connection
|
|
end
|
|
|
|
def connection
|
|
Thread.current["schema_cached_connection"]
|
|
end
|
|
end
|
|
end
|
|
end
|