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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ff4bc7184278bc6c6669e532f036c74e117657510a701705b8850141f3a59ed
4
- data.tar.gz: de8307fbf47c7660b3a7c2563f5b399cd55d4b524c23550d383073fb49df68f2
3
+ metadata.gz: 5e39298a87b7d9af49c9bb2dd6bffc0174a569d994432fc86c6668f00d7b8b4b
4
+ data.tar.gz: 585c11f47cb258259b91ff9b3f7917ff83d06b7b1a7010732174790adac45917
5
5
  SHA512:
6
- metadata.gz: b9c651428a0fccf0a02f16a8d3ab587cf54f6f3f53156e89d5eea3800ca69a2228e3fdce72215526178fab80ecad3b3b8621cc381060c784ead4259910ad3f6f
7
- data.tar.gz: 2ba6dd00743e9819a1bf5edfc35b7fdfa5d8c34a11cc4f4c563b55275fe45d4d7d0b706aa9f3b3b2516b60c98b811f81e647c318b668e67b43297f04bbdfe3fc
6
+ metadata.gz: 527754102963062a8988612b29f92d2f6bf7f1d4e8084536983c7bf6fdbdaf92db5ae17e4d5e6ee7ae92865b5ad4e98a13a9710675dec85d8365acfeae4e7e72
7
+ data.tar.gz: 81c561439791aab9164e62d928d2a3ea60d9bbf9deb6217938fd36632d842e138106c11aacfb951ee48435a02bb0503d542ff861b736f9fcdac7ebfebdb5d6f2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.2.4
2
+
3
+ - Added support for Aurora MySQL replication lag
4
+ - Added more logging
5
+
1
6
  ## 0.2.3
2
7
 
3
8
  - Added support for Makara 0.4
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
@@ -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
- warn "[distribute_reads] Multiple replicas available, lag only reported for one"
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
- status = connection.exec_query("SHOW SLAVE STATUS").to_hash.first
63
- status ? status["Seconds_Behind_Master"].to_f : 0.0
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
- raise DistributeReads::NoReplicasAvailable, "No replicas available" if blacklisted && Thread.current[:distribute_reads][:failover] == false
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, "Replica lag over #{max_lag} seconds#{options[:lag_on] ? " on #{base_model.name} connection" : ""}"
33
+ raise DistributeReads::TooMuchLag, message
31
34
  end
32
35
  end
33
36
  end
34
37
  end
35
38
 
36
39
  value = yield
37
- warn "[distribute_reads] Call `to_a` inside block to execute query on replica" if value.is_a?(ActiveRecord::Relation) && !previous_value
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
@@ -18,7 +18,7 @@ module DistributeReads
18
18
 
19
19
  class_methods do
20
20
  def distribute_reads(*args)
21
- around_perform do |job, block|
21
+ around_perform do |_job, block|
22
22
  distribute_reads(*args) { block.call }
23
23
  end
24
24
  end
@@ -1,3 +1,3 @@
1
1
  module DistributeReads
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.4"
3
3
  end
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.3
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-05-24 00:00:00.000000000 Z
11
+ date: 2018-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: makara