distribute_reads 0.2.3 → 0.2.4
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 +5 -0
- data/README.md +16 -8
- data/lib/distribute_reads.rb +20 -3
- data/lib/distribute_reads/appropriate_pool.rb +8 -1
- data/lib/distribute_reads/global_methods.rb +5 -2
- data/lib/distribute_reads/job_methods.rb +1 -1
- data/lib/distribute_reads/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5e39298a87b7d9af49c9bb2dd6bffc0174a569d994432fc86c6668f00d7b8b4b
|
|
4
|
+
data.tar.gz: 585c11f47cb258259b91ff9b3f7917ff83d06b7b1a7010732174790adac45917
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 527754102963062a8988612b29f92d2f6bf7f1d4e8084536983c7bf6fdbdaf92db5ae17e4d5e6ee7ae92865b5ad4e98a13a9710675dec85d8365acfeae4e7e72
|
|
7
|
+
data.tar.gz: 81c561439791aab9164e62d928d2a3ea60d9bbf9deb6217938fd36632d842e138106c11aacfb951ee48435a02bb0503d542ff861b736f9fcdac7ebfebdb5d6f2
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -72,11 +72,25 @@ end
|
|
|
72
72
|
|
|
73
73
|
You can pass any options as well.
|
|
74
74
|
|
|
75
|
+
## Lazy Evaluation
|
|
76
|
+
|
|
77
|
+
ActiveRecord uses [lazy evaluation](https://www.theodinproject.com/courses/ruby-on-rails/lessons/active-record-queries), which can delay the execution of a query to outside of a `distribute_reads` block. In this case, the primary will be used.
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
users = distribute_reads { User.where(orders_count: 1) } # not executed yet
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Call `to_a` inside the block ensure the query runs on a replica.
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
users = distribute_reads { User.where(orders_count: 1).to_a }
|
|
87
|
+
```
|
|
88
|
+
|
|
75
89
|
## Options
|
|
76
90
|
|
|
77
91
|
### Replica Lag
|
|
78
92
|
|
|
79
|
-
Raise an error when replica lag is too high
|
|
93
|
+
Raise an error when replica lag is too high (specified in seconds)
|
|
80
94
|
|
|
81
95
|
```ruby
|
|
82
96
|
distribute_reads(max_lag: 3) do
|
|
@@ -131,12 +145,6 @@ At some point, you may wish to distribute reads by default.
|
|
|
131
145
|
DistributeReads.by_default = true
|
|
132
146
|
```
|
|
133
147
|
|
|
134
|
-
Once you do this, Makara will use the Rails cache to track its state. To reduce load on the Rails cache, use a write-through cache in front of it.
|
|
135
|
-
|
|
136
|
-
```ruby
|
|
137
|
-
Makara::Cache.store = DistributeReads::CacheStore.new
|
|
138
|
-
```
|
|
139
|
-
|
|
140
148
|
To make queries go to primary, use:
|
|
141
149
|
|
|
142
150
|
```ruby
|
|
@@ -147,7 +155,7 @@ end
|
|
|
147
155
|
|
|
148
156
|
## Reference
|
|
149
157
|
|
|
150
|
-
Get replication lag
|
|
158
|
+
Get replication lag in seconds
|
|
151
159
|
|
|
152
160
|
```ruby
|
|
153
161
|
DistributeReads.replication_lag
|
data/lib/distribute_reads.rb
CHANGED
|
@@ -32,7 +32,7 @@ module DistributeReads
|
|
|
32
32
|
|
|
33
33
|
replica_pool = connection.instance_variable_get(:@slave_pool)
|
|
34
34
|
if replica_pool && replica_pool.connections.size > 1
|
|
35
|
-
|
|
35
|
+
log "Multiple replicas available, lag only reported for one"
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
if %w(PostgreSQL PostGIS).include?(connection.adapter_name)
|
|
@@ -59,8 +59,21 @@ module DistributeReads
|
|
|
59
59
|
begin
|
|
60
60
|
# makara doesn't send SHOW queries to replica, so we must force it
|
|
61
61
|
Thread.current[:distribute_reads][:replica] = true
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
|
|
63
|
+
@aurora_mysql ||= {}
|
|
64
|
+
cache_key = connection.pool.object_id
|
|
65
|
+
|
|
66
|
+
unless @aurora_mysql.key?(cache_key)
|
|
67
|
+
@aurora_mysql[cache_key] = connection.exec_query("SHOW VARIABLES LIKE 'aurora_version'").to_hash.any?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if @aurora_mysql[cache_key]
|
|
71
|
+
status = connection.exec_query("SELECT Replica_lag_in_msec FROM mysql.ro_replica_status WHERE Server_id = @@aurora_server_id").to_hash.first
|
|
72
|
+
status ? status["Replica_lag_in_msec"].to_f / 1000.0 : 0.0
|
|
73
|
+
else
|
|
74
|
+
status = connection.exec_query("SHOW SLAVE STATUS").to_hash.first
|
|
75
|
+
status ? status["Seconds_Behind_Master"].to_f : 0.0
|
|
76
|
+
end
|
|
64
77
|
ensure
|
|
65
78
|
Thread.current[:distribute_reads][:replica] = replica_value
|
|
66
79
|
end
|
|
@@ -69,6 +82,10 @@ module DistributeReads
|
|
|
69
82
|
end
|
|
70
83
|
end
|
|
71
84
|
|
|
85
|
+
def self.log(message)
|
|
86
|
+
warn "[distribute_reads] #{message}"
|
|
87
|
+
end
|
|
88
|
+
|
|
72
89
|
# private
|
|
73
90
|
def self.makara3?
|
|
74
91
|
unless defined?(@makara3)
|
|
@@ -5,12 +5,19 @@ module DistributeReads
|
|
|
5
5
|
if Thread.current[:distribute_reads][:replica]
|
|
6
6
|
if @slave_pool.completely_blacklisted?
|
|
7
7
|
raise DistributeReads::NoReplicasAvailable, "No replicas available" if Thread.current[:distribute_reads][:failover] == false
|
|
8
|
+
DistributeReads.log "No replicas available. Falling back to master pool."
|
|
8
9
|
@master_pool
|
|
9
10
|
else
|
|
10
11
|
@slave_pool
|
|
11
12
|
end
|
|
12
13
|
elsif Thread.current[:distribute_reads][:primary] || needs_master?(*args) || (blacklisted = @slave_pool.completely_blacklisted?)
|
|
13
|
-
|
|
14
|
+
if blacklisted
|
|
15
|
+
if Thread.current[:distribute_reads][:failover] == false
|
|
16
|
+
raise DistributeReads::NoReplicasAvailable, "No replicas available"
|
|
17
|
+
else
|
|
18
|
+
DistributeReads.log "No replicas available. Falling back to master pool."
|
|
19
|
+
end
|
|
20
|
+
end
|
|
14
21
|
stick_to_master(*args) if DistributeReads.by_default
|
|
15
22
|
@master_pool
|
|
16
23
|
elsif in_transaction?
|
|
@@ -21,20 +21,23 @@ module DistributeReads
|
|
|
21
21
|
if max_lag && !options[:primary]
|
|
22
22
|
Array(options[:lag_on] || [ActiveRecord::Base]).each do |base_model|
|
|
23
23
|
if DistributeReads.lag(connection: base_model.connection) > max_lag
|
|
24
|
+
message = "Replica lag over #{max_lag} seconds#{options[:lag_on] ? " on #{base_model.name} connection" : ""}"
|
|
25
|
+
|
|
24
26
|
if options[:lag_failover]
|
|
25
27
|
# TODO possibly per connection
|
|
26
28
|
Thread.current[:distribute_reads][:primary] = true
|
|
27
29
|
Thread.current[:distribute_reads][:replica] = false
|
|
30
|
+
DistributeReads.log "#{message}. Falling back to master pool."
|
|
28
31
|
break
|
|
29
32
|
else
|
|
30
|
-
raise DistributeReads::TooMuchLag,
|
|
33
|
+
raise DistributeReads::TooMuchLag, message
|
|
31
34
|
end
|
|
32
35
|
end
|
|
33
36
|
end
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
value = yield
|
|
37
|
-
|
|
40
|
+
DistributeReads.log "Call `to_a` inside block to execute query on replica" if value.is_a?(ActiveRecord::Relation) && !previous_value
|
|
38
41
|
value
|
|
39
42
|
ensure
|
|
40
43
|
Thread.current[:distribute_reads] = previous_value
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: distribute_reads
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Kane
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-
|
|
11
|
+
date: 2018-11-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: makara
|