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 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