Module: Apartment::Patches::ConnectionHandling
- Defined in:
- lib/apartment/patches/connection_handling.rb
Overview
Prepended on ActiveRecord::Base (singleton class) to intercept connection_pool lookups. When Apartment::Current.tenant is set, returns a tenant-specific pool keyed by “tenant:role”, with config resolved by the adapter using the current role’s base config.
Instance Method Summary collapse
-
#connection_pool ⇒ Object
rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity.
Instance Method Details
#connection_pool ⇒ Object
rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/apartment/patches/connection_handling.rb', line 12 def connection_pool # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity tenant = Apartment::Current.tenant cfg = Apartment.config return super if tenant.nil? || cfg.nil? return super if tenant.to_s == cfg.default_tenant.to_s return super unless Apartment.pool_manager # Skip tenant override for Apartment pinned models. # Uses explicit registry (not connection_specification_name heuristic) # because ApplicationRecord subclasses have a different spec name than # ActiveRecord::Base while sharing the same pool. return super if self != ActiveRecord::Base && Apartment.pinned_model?(self) role = ActiveRecord::Base.current_role pool_key = "#{tenant}:#{role}" Apartment.pool_manager.fetch_or_create(pool_key) do # Resolve base config from the current role's default pool when available. # Falls back to nil (adapter uses its own base_config) when the default pool # is not accessible — e.g., in worker threads during parallel migration where # the ConnectionHandler may not have the pool registered for this context. # NOTE: `super` must be called here (not in a helper) because it refers to # the original connection_pool method on AR::Base, which only resolves from # the prepended method scope. base = begin default_pool = super default_pool.db_config.configuration_hash.stringify_keys rescue ActiveRecord::ConnectionNotEstablished nil end config = Apartment.adapter.validated_connection_config(tenant, base_config_override: base) prefix = cfg.shard_key_prefix shard_key = :"#{prefix}_#{pool_key}" db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new( cfg.rails_env_name, "#{prefix}_#{pool_key}", config ) pool = ActiveRecord::Base.connection_handler.establish_connection( db_config, owner_name: ActiveRecord::Base, role: role, shard: shard_key ) raise(Apartment::PendingMigrationError, tenant) if check_pending_migrations?(pool) load_tenant_schema_cache(tenant, pool) if cfg.schema_cache_per_tenant pool end rescue Apartment::ApartmentError raise rescue StandardError => e raise(Apartment::ApartmentError, "Failed to resolve connection pool for tenant '#{tenant}': #{e.class}: #{e.}") end |