active_record_proxy_adapters 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -18
- data/Dockerfile +1 -1
- data/README.md +0 -2
- data/db/postgresql_structure.sql +6 -16
- data/docker-compose.yml +1 -0
- data/lib/active_record_proxy_adapters/configuration.rb +22 -4
- data/lib/active_record_proxy_adapters/log_subscriber.rb +41 -0
- data/lib/active_record_proxy_adapters/primary_replica_proxy.rb +2 -31
- data/lib/active_record_proxy_adapters/version.rb +1 -1
- data/postgres_primary.dockerfile +1 -1
- data/postgres_replica.dockerfile +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5312effcf68a3305eb5e7804440112433f5b6837d6b71e7d122145eac4741619
|
4
|
+
data.tar.gz: 50586657daa02e76dfffebbe1faf8df5093198471faf847cec97cd16634c0c17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 707b80a3618328639126d13f3f76bb8123105019b3e30c75f15c66a66a88d49aa5de4301fe70b25ff5356ef37e54ebff896f4cab0160cadbb79d08ae9cf0dc4e
|
7
|
+
data.tar.gz: 6b84984e33cf87abe9a12f5553bccffc32e2a9563a0c859c488cdae4be4c3a019ffce01242648620c67bb85a16dc61d982f0be8ecba83943f01c718e067743dc
|
data/CHANGELOG.md
CHANGED
@@ -1,37 +1,26 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
- Handle PendingMigrationConnection introduced by Rails 7.2 and backported to Rails 7.1
|
4
|
-
- Stick to same connection throughout request span
|
5
|
-
|
6
|
-
## [0.2.1] - 2025-01-02
|
7
|
-
|
8
|
-
- Fix replica connection pool getter when specific connection name is not found https://github.com/Nasdaq/active_record_proxy_adapters/commit/847e150dd21c5bc619745ee1d9d8fcaa9b8f2eea
|
9
|
-
|
10
3
|
## [0.2.0] - 2024-12-24
|
11
4
|
|
12
|
-
- Add custom log subscriber to tag queries based on the adapter being used
|
13
|
-
|
14
|
-
## [0.1.4] - 2025-01-02
|
15
|
-
|
16
|
-
- Fix replica connection pool getter when specific connection name is not found https://github.com/Nasdaq/active_record_proxy_adapters/commit/88b32a282b54d420e652f638656dbcf063ac8796
|
5
|
+
- Add custom log subscriber to tag queries based on the adapter being used (68b8c1f4191388eb957bf12e0f84289da667e940)
|
17
6
|
|
18
7
|
## [0.1.3] - 2024-12-24
|
19
8
|
|
20
|
-
- Fix replica connection pool getter when database configurations have multiple replicas
|
21
|
-
- Retrieve replica pool without checking out a connection
|
9
|
+
- Fix replica connection pool getter when database configurations have multiple replicas (ea5a33997da45ac073f166b3fbd2d12426053cd6)
|
10
|
+
- Retrieve replica pool without checking out a connection (6470ef58e851082ae1f7a860ecdb5b451ef903c8)
|
22
11
|
|
23
12
|
## [0.1.2] - 2024-12-16
|
24
13
|
|
25
|
-
- Fix CTE regex matcher
|
14
|
+
- Fix CTE regex matcher (4b1d10bfd952fb1f5b102de8cc1a5bd05d25f5e9)
|
26
15
|
|
27
16
|
## [0.1.1] - 2024-11-27
|
28
17
|
|
29
|
-
- Enable RubyGems MFA
|
18
|
+
- Enable RubyGems MFA (2a71b1f4354fb966cc0aa68231ca5837814e07ee)
|
30
19
|
|
31
20
|
## [0.1.0] - 2024-11-19
|
32
21
|
|
33
|
-
- Add PostgreSQLProxyAdapter
|
22
|
+
- Add PostgreSQLProxyAdapter (2b3bb9f7359139519b32af3018ceb07fed8c6b33)
|
34
23
|
|
35
24
|
## [0.1.0.rc2] - 2024-10-28
|
36
25
|
|
37
|
-
- Add PostgreSQLProxyAdapter
|
26
|
+
- Add PostgreSQLProxyAdapter (2b3bb9f7359139519b32af3018ceb07fed8c6b33)
|
data/Dockerfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# ActiveRecordProxyAdapters
|
2
2
|
|
3
|
-
[](https://github.com/Nasdaq/active_record_proxy_adapters/actions/workflows/test.yml)
|
4
|
-
|
5
3
|
A set of ActiveRecord adapters that leverage Rails native multiple database setup to allow automatic connection switching from _one_ primary pool to _one_ replica pool at the database statement level.
|
6
4
|
|
7
5
|
## Installation
|
data/db/postgresql_structure.sql
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
SET statement_timeout = 0;
|
2
2
|
SET lock_timeout = 0;
|
3
3
|
SET idle_in_transaction_session_timeout = 0;
|
4
|
-
SET transaction_timeout = 0;
|
5
4
|
SET client_encoding = 'UTF8';
|
6
5
|
SET standard_conforming_strings = on;
|
7
6
|
SELECT pg_catalog.set_config('search_path', '', false);
|
@@ -10,18 +9,16 @@ SET xmloption = content;
|
|
10
9
|
SET client_min_messages = warning;
|
11
10
|
SET row_security = off;
|
12
11
|
|
13
|
-
SET default_tablespace = '';
|
14
|
-
|
15
|
-
SET default_table_access_method = heap;
|
16
|
-
|
17
12
|
--
|
18
|
-
-- Name:
|
13
|
+
-- Name: public; Type: SCHEMA; Schema: -; Owner: -
|
19
14
|
--
|
20
15
|
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
-- *not* creating schema, since initdb creates it
|
17
|
+
|
18
|
+
|
19
|
+
SET default_tablespace = '';
|
24
20
|
|
21
|
+
SET default_table_access_method = heap;
|
25
22
|
|
26
23
|
--
|
27
24
|
-- Name: users; Type: TABLE; Schema: public; Owner: -
|
@@ -71,13 +68,6 @@ ALTER TABLE ONLY public.users
|
|
71
68
|
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
|
72
69
|
|
73
70
|
|
74
|
-
--
|
75
|
-
-- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: -
|
76
|
-
--
|
77
|
-
|
78
|
-
CREATE UNIQUE INDEX unique_schema_migrations ON public.schema_migrations USING btree (version);
|
79
|
-
|
80
|
-
|
81
71
|
--
|
82
72
|
-- PostgreSQL database dump complete
|
83
73
|
--
|
data/docker-compose.yml
CHANGED
@@ -5,8 +5,10 @@ require "active_support/core_ext/integer/time"
|
|
5
5
|
module ActiveRecordProxyAdapters
|
6
6
|
# Provides a global configuration object to configure how the proxy should behave.
|
7
7
|
class Configuration
|
8
|
-
PROXY_DELAY
|
9
|
-
CHECKOUT_TIMEOUT
|
8
|
+
PROXY_DELAY = 2.seconds.freeze
|
9
|
+
CHECKOUT_TIMEOUT = 2.seconds.freeze
|
10
|
+
LOG_SUBSCRIBER_PRIMARY_PREFIX = proc { |event| "#{event.payload[:connection].class::ADAPTER_NAME} Primary" }.freeze
|
11
|
+
LOG_SUBSCRIBER_REPLICA_PREFIX = proc { |event| "#{event.payload[:connection].class::ADAPTER_NAME} Replica" }.freeze
|
10
12
|
|
11
13
|
# @return [ActiveSupport::Duration] How long the proxy should reroute all read requests to the primary database
|
12
14
|
# since the latest write. Defaults to PROXY_DELAY.
|
@@ -15,9 +17,25 @@ module ActiveRecordProxyAdapters
|
|
15
17
|
# Defaults to CHECKOUT_TIMEOUT.
|
16
18
|
attr_accessor :checkout_timeout
|
17
19
|
|
20
|
+
# @return [Proc] Prefix for the log subscriber when the primary database is used.
|
21
|
+
attr_reader :log_subscriber_primary_prefix
|
22
|
+
|
23
|
+
# @return [Proc] Prefix for the log subscriber when the replica database is used.
|
24
|
+
attr_reader :log_subscriber_replica_prefix
|
25
|
+
|
18
26
|
def initialize
|
19
|
-
self.proxy_delay
|
20
|
-
self.checkout_timeout
|
27
|
+
self.proxy_delay = PROXY_DELAY
|
28
|
+
self.checkout_timeout = CHECKOUT_TIMEOUT
|
29
|
+
self.log_subscriber_primary_prefix = LOG_SUBSCRIBER_PRIMARY_PREFIX
|
30
|
+
self.log_subscriber_replica_prefix = LOG_SUBSCRIBER_REPLICA_PREFIX
|
31
|
+
end
|
32
|
+
|
33
|
+
def log_subscriber_primary_prefix=(prefix)
|
34
|
+
@log_subscriber_primary_prefix = prefix.is_a?(Proc) ? prefix : proc { prefix.to_s }
|
35
|
+
end
|
36
|
+
|
37
|
+
def log_subscriber_replica_prefix=(prefix)
|
38
|
+
@log_subscriber_replica_prefix = prefix.is_a?(Proc) ? prefix : proc { prefix.to_s }
|
21
39
|
end
|
22
40
|
end
|
23
41
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordProxyAdapters
|
4
|
+
class LogSubscriber < ActiveRecord::LogSubscriber # rubocop:disable Style/Documentation
|
5
|
+
attach_to :active_record
|
6
|
+
|
7
|
+
IGNORE_PAYLOAD_NAMES = %w[SCHEMA EXPLAIN].freeze
|
8
|
+
|
9
|
+
def sql(event)
|
10
|
+
payload = event.payload
|
11
|
+
name = payload[:name]
|
12
|
+
unless IGNORE_PAYLOAD_NAMES.include?(name)
|
13
|
+
name = [database_instance_prefix_for(event), name].compact.join(" ")
|
14
|
+
payload[:name] = name
|
15
|
+
end
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def database_instance_prefix_for(event)
|
22
|
+
connection = event.payload[:connection]
|
23
|
+
config = connection.instance_variable_get(:@config)
|
24
|
+
prefix = if config[:replica] || config["replica"]
|
25
|
+
log_subscriber_replica_prefix
|
26
|
+
else
|
27
|
+
log_subscriber_primary_prefix
|
28
|
+
end
|
29
|
+
|
30
|
+
"[#{prefix.call(event)}]"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
delegate :log_subscriber_primary_prefix, :log_subscriber_replica_prefix, to: :config
|
36
|
+
|
37
|
+
def config
|
38
|
+
ActiveRecordProxyAdapters.config
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -62,7 +62,7 @@ module ActiveRecordProxyAdapters
|
|
62
62
|
|
63
63
|
attr_reader :primary_connection, :last_write_at, :active_record_context
|
64
64
|
|
65
|
-
delegate :connection_handler, to: :connection_class
|
65
|
+
delegate :connection_handler, :connected_to_stack, to: :connection_class
|
66
66
|
delegate :reading_role, :writing_role, to: :active_record_context
|
67
67
|
|
68
68
|
def replica_pool_unavailable?
|
@@ -70,18 +70,9 @@ module ActiveRecordProxyAdapters
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def replica_pool
|
73
|
-
# use default handler if the connection pool for specific class is not found
|
74
|
-
specific_replica_pool || default_replica_pool
|
75
|
-
end
|
76
|
-
|
77
|
-
def specific_replica_pool
|
78
73
|
connection_handler.retrieve_connection_pool(connection_class.name, role: reading_role)
|
79
74
|
end
|
80
75
|
|
81
|
-
def default_replica_pool
|
82
|
-
connection_handler.retrieve_connection_pool(ActiveRecord::Base.name, role: reading_role)
|
83
|
-
end
|
84
|
-
|
85
76
|
def connection_class
|
86
77
|
active_record_context.connection_class_for(primary_connection)
|
87
78
|
end
|
@@ -120,25 +111,11 @@ module ActiveRecordProxyAdapters
|
|
120
111
|
[reading_role, writing_role].include?(role) ? role : nil
|
121
112
|
end
|
122
113
|
|
123
|
-
def connected_to_stack
|
124
|
-
return connection_class.connected_to_stack if connection_class.respond_to?(:connected_to_stack)
|
125
|
-
|
126
|
-
# handle Rails 7.2+ pending migrations Connection
|
127
|
-
return [{ role: writing_role }] if pending_migration_connection?
|
128
|
-
|
129
|
-
[]
|
130
|
-
end
|
131
|
-
|
132
|
-
def pending_migration_connection?
|
133
|
-
active_record_context.active_record_v7_1_or_greater? &&
|
134
|
-
connection_class.name == "ActiveRecord::PendingMigrationConnection"
|
135
|
-
end
|
136
|
-
|
137
114
|
def connection_for(role, sql_string)
|
138
115
|
connection = primary_connection if role == writing_role || replica_pool_unavailable?
|
139
116
|
connection ||= checkout_replica_connection
|
140
117
|
|
141
|
-
result =
|
118
|
+
result = yield(connection)
|
142
119
|
|
143
120
|
update_primary_latest_write_timestamp if !replica_connection?(connection) && write_statement?(sql_string)
|
144
121
|
|
@@ -147,12 +124,6 @@ module ActiveRecordProxyAdapters
|
|
147
124
|
replica_connection?(connection) && replica_pool.checkin(connection)
|
148
125
|
end
|
149
126
|
|
150
|
-
def connected_to(role:, &block)
|
151
|
-
return block.call unless connection_class.respond_to?(:connected_to)
|
152
|
-
|
153
|
-
connection_class.connected_to(role:, &block)
|
154
|
-
end
|
155
|
-
|
156
127
|
def replica_connection?(connection)
|
157
128
|
connection && connection != primary_connection
|
158
129
|
end
|
data/postgres_primary.dockerfile
CHANGED
data/postgres_replica.dockerfile
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_proxy_adapters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Cruz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- lib/active_record_proxy_adapters/configuration.rb
|
78
78
|
- lib/active_record_proxy_adapters/connection_handling.rb
|
79
79
|
- lib/active_record_proxy_adapters/hijackable.rb
|
80
|
+
- lib/active_record_proxy_adapters/log_subscriber.rb
|
80
81
|
- lib/active_record_proxy_adapters/postgresql_proxy.rb
|
81
82
|
- lib/active_record_proxy_adapters/primary_replica_proxy.rb
|
82
83
|
- lib/active_record_proxy_adapters/railtie.rb
|