distribute_reads 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|