em-hiredis-sentinel 0.1.3 → 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/README.md +30 -7
- data/em-hiredis-sentinel.gemspec +2 -3
- data/lib/em-hiredis-sentinel/redis_client.rb +352 -0
- data/lib/em-hiredis-sentinel/version.rb +1 -1
- data/lib/em-hiredis-sentinel.rb +1 -13
- metadata +3 -7
- data/examples/getting_started.rb +0 -28
- data/examples/pubsub.rb +0 -21
- data/lib/em-hiredis-sentinel/base_client.rb +0 -129
- data/lib/em-hiredis-sentinel/client.rb +0 -11
- data/lib/em-hiredis-sentinel/pubsub_client.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 104a38dedcc6966ffbc70bbc9d75aa9f4575355c
|
4
|
+
data.tar.gz: 33f24f9988e59d6949f2dab4061c7cbe749b7bca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bf1bb72150d1bf7ccd0b68e2c6a9c49c8c09bb19c79820f6c6d5ad25857d4dc56a9f1bb8a8360532940e899ea7277959eda4cd179e26fd7cd66de66d9b54a7b
|
7
|
+
data.tar.gz: 0e4f3e54b0cdf3a8cf2c2e67a2a841e194a230ee4b983e11bce6cc70421f4c40142178ff662c04a534f1d054e47f753bf12bca9b462e7a7efabeb3925b382a0b
|
data/README.md
CHANGED
@@ -19,13 +19,36 @@ Or install it yourself as:
|
|
19
19
|
## Usage
|
20
20
|
|
21
21
|
require 'em-hiredis-sentinel'
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
EM.run do
|
23
|
+
redis = EM::Hiredis::Sentinel::RedisClient.new(sentinels:[
|
24
|
+
'redis://sentinel1.example.net',
|
25
|
+
'xyz://sentinel2.example.net:26378',
|
26
|
+
{host:'sentinel3.example.net'},
|
27
|
+
{host:'sentinel4.example.net', port:26380},
|
28
|
+
{url:'blah://sentinel5.example.net:26381'},
|
29
|
+
{url:'ignored://sentinel6.example.net'}
|
30
|
+
],
|
31
|
+
master_name:'mymaster'
|
32
|
+
)
|
33
|
+
redis.connect
|
34
|
+
counter = 0
|
35
|
+
t = nil
|
36
|
+
|
37
|
+
redis.pubsub.on(:connected) do
|
38
|
+
p "connect callback"
|
39
|
+
|
40
|
+
t = EM.add_periodic_timer(2) do
|
41
|
+
counter += 1
|
42
|
+
redis.pubsub.publish("test", "test-#{counter}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
redis.pubsub.on(:disconnected) do
|
47
|
+
p "disconnect callback"
|
48
|
+
t.cancel
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
29
52
|
|
30
53
|
|
31
54
|
## Contributing
|
data/em-hiredis-sentinel.gemspec
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
4
3
|
require 'em-hiredis-sentinel/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
@@ -0,0 +1,352 @@
|
|
1
|
+
require 'em-hiredis'
|
2
|
+
|
3
|
+
module EventMachine::Hiredis::Sentinel
|
4
|
+
class RedisClient < EventMachine::Hiredis::Client
|
5
|
+
alias :super_connect :connect #to ref super's connect
|
6
|
+
|
7
|
+
def initialize(sentinels:[], master_name:'mymaster', db:0, password:nil)
|
8
|
+
@master_name = master_name
|
9
|
+
@sentinels = _parse_sentinel_options(sentinels)
|
10
|
+
p @sentinels
|
11
|
+
raise "Need at least 1 sentinel" if @sentinels.nil? || @sentinels.count < 1
|
12
|
+
@sentinels.uniq! {|h| h.values_at(:host, :port) }
|
13
|
+
@sentinels.shuffle! #try to randomize
|
14
|
+
|
15
|
+
init_sentinel_client
|
16
|
+
|
17
|
+
super(nil, nil, password, db)
|
18
|
+
init_master_client
|
19
|
+
|
20
|
+
#waits for connect to do anything
|
21
|
+
end
|
22
|
+
|
23
|
+
#override bc of auto .connect in super
|
24
|
+
def pubsub
|
25
|
+
#EM::Hiredis.logger.debug("pubsub")
|
26
|
+
@pubsub ||= begin
|
27
|
+
@with_pubsub = true
|
28
|
+
init_master_pubsub_client
|
29
|
+
update_master_pubsub_client(@master_client.host, @master_client.port) if @master_client.connected?
|
30
|
+
@master_pubsub_client
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def connect(with_pubsub:false)
|
35
|
+
@with_pubsub ||= with_pubsub
|
36
|
+
try_next_sentinel
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def init_sentinel_client
|
43
|
+
@sentinel_client = EM::Hiredis::Client.new
|
44
|
+
|
45
|
+
@sentinel_client.on(:connected) do
|
46
|
+
EM::Hiredis.logger.debug("Connected to sentinel")
|
47
|
+
emit(:sentinel_connected)
|
48
|
+
|
49
|
+
EM.next_tick do
|
50
|
+
#wait till sentinel connected to init pubsub
|
51
|
+
@sentinel_pubsub_client ?
|
52
|
+
update_sentinel_pubsub_client(@sentinel_client.host, @sentinel_client.port) :
|
53
|
+
init_sentinel_pubsub_client #auto connects
|
54
|
+
|
55
|
+
discover_master unless @master_client.connected?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@sentinel_client.on(:failed) do
|
60
|
+
EM::Hiredis.logger.debug("Failed sentinel")
|
61
|
+
@sentinel_client.close_connection
|
62
|
+
emit(:sentinel_failed)
|
63
|
+
|
64
|
+
EM.add_timer(0.5) do
|
65
|
+
try_next_sentinel
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
@sentinel_client.on(:disconnected) do
|
70
|
+
EM::Hiredis.logger.debug("Disconnected from sentinel")
|
71
|
+
emit(:sentinel_disconnected)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def init_sentinel_pubsub_client
|
76
|
+
@sentinel_pubsub_client = @sentinel_client.pubsub #lazy init, this will auto try connect
|
77
|
+
@sentinel_pubsub_client.on(:connected) do
|
78
|
+
EM::Hiredis.logger.debug("Connected to sentinel for pubsub")
|
79
|
+
emit(:sentinel_pubsub_connected)
|
80
|
+
end
|
81
|
+
|
82
|
+
@sentinel_pubsub_client.on(:failed) do
|
83
|
+
EM::Hiredis.logger.debug("#{@name} pubsub failed")
|
84
|
+
@sentinel_pubsub_client.close_connection
|
85
|
+
emit(:sentinel_pubsub_failed)
|
86
|
+
end
|
87
|
+
|
88
|
+
@sentinel_pubsub_client.on(:disconnected) do
|
89
|
+
EM::Hiredis.logger.debug("Disconnected from sentinel for pubsub")
|
90
|
+
emit(:sentinel_pubsub_disconnected)
|
91
|
+
end
|
92
|
+
|
93
|
+
watch_sentinel
|
94
|
+
end
|
95
|
+
|
96
|
+
def watch_sentinel
|
97
|
+
#EM::Hiredis.logger.debug("watch_sentinel")
|
98
|
+
|
99
|
+
#@sentinel_pubsub_client.punsubscribe('*') #in case already subscribe?
|
100
|
+
@sentinel_pubsub_client.psubscribe('*') do |channel, message|
|
101
|
+
EM::Hiredis.logger.debug("SENTINEL PUBSUB #{channel} #{message}")
|
102
|
+
|
103
|
+
if channel == '+switch-master'
|
104
|
+
master_name, old_host, old_port, new_host, new_port = message.split(" ")
|
105
|
+
|
106
|
+
if master_name == @master_name
|
107
|
+
EM::Hiredis.logger.debug("Failover: #{old_host}:#{old_port} => #{new_host}:#{new_port}")
|
108
|
+
update_master_client(new_host, new_port.to_i)
|
109
|
+
end
|
110
|
+
|
111
|
+
elsif channel == '-odown' #TODO necessary?
|
112
|
+
type, master_name, host, port = message.split(" ")
|
113
|
+
|
114
|
+
if master_name == @master_name #&& type == 'master' type is always master for odown
|
115
|
+
EM::Hiredis.logger.debug("-ODOWN #{connected?}")
|
116
|
+
update_master_client(host, port.to_i)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def init_master_client
|
123
|
+
@master_client = self
|
124
|
+
@master_client.on(:connected) do
|
125
|
+
EM::Hiredis.logger.debug("#{@name} Connected to master")
|
126
|
+
@is_master_updating = false
|
127
|
+
|
128
|
+
#TODO confirm is master with ROLE (2.8.12)
|
129
|
+
emit(:master_connected)
|
130
|
+
|
131
|
+
EM.next_tick do
|
132
|
+
if @with_pubsub
|
133
|
+
if @master_pubsub_client
|
134
|
+
update_master_pubsub_client(@master_client.host, @master_client.port)
|
135
|
+
else
|
136
|
+
pubsub
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
refresh_sentinels_list #TODO maybe do on sentinel connect
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
@master_client.on(:failed) do
|
145
|
+
EM::Hiredis.logger.debug("#{@name} failed")
|
146
|
+
@is_master_updating = false
|
147
|
+
@master_client.close_connection
|
148
|
+
emit(:master_failed)
|
149
|
+
queue_discover_master
|
150
|
+
end
|
151
|
+
|
152
|
+
@master_client.on(:disconnected) do
|
153
|
+
EM::Hiredis.logger.debug("#{@name} Disconnected from master")
|
154
|
+
emit(:master_disconnected)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def init_master_pubsub_client
|
159
|
+
#EM::Hiredis.logger.debug("init_master_pubsub_client")
|
160
|
+
@master_pubsub_client = EM::Hiredis::PubsubClient.new(@master_client.host,
|
161
|
+
@master_client.port,
|
162
|
+
@master_client.password,
|
163
|
+
@master_client.db
|
164
|
+
)
|
165
|
+
@master_pubsub_client.on(:connected) do
|
166
|
+
EM::Hiredis.logger.debug("#{@name} Connected to master for pubsub")
|
167
|
+
emit(:master_pubsub_connected)
|
168
|
+
end
|
169
|
+
|
170
|
+
@master_pubsub_client.on(:failed) do
|
171
|
+
EM::Hiredis.logger.debug("#{@name} pubsub failed")
|
172
|
+
@master_pubsub_client.close_connection
|
173
|
+
emit(:master_pubsub_failed)
|
174
|
+
end
|
175
|
+
|
176
|
+
@master_pubsub_client.on(:disconnected) do
|
177
|
+
EM::Hiredis.logger.debug("#{@name} Disconnected from master for pubsub")
|
178
|
+
emit(:master_pubsub_disconnected)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def update_sentinel_client(host, port)
|
183
|
+
EM::Hiredis.logger.debug("update_sentinel_client #{host}, #{port}")
|
184
|
+
|
185
|
+
@sentinel_client.configure("redis://#{host}:#{port}")
|
186
|
+
|
187
|
+
if @sentinel_client.instance_variable_get(:@connection)
|
188
|
+
@sentinel_client.close_connection
|
189
|
+
EM.next_tick {
|
190
|
+
@sentinel_client.reconnect_connection
|
191
|
+
}
|
192
|
+
else
|
193
|
+
EM::Hiredis.logger.debug("FIRST SENTINEL CONNECT ATTEMPT")
|
194
|
+
EM.next_tick {
|
195
|
+
@sentinel_client.connect #first time, bc baseclient isnt expecting deferred connecting
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
rescue => e
|
200
|
+
EM::Hiredis.logger.warn(e)
|
201
|
+
EM.next_tick do
|
202
|
+
try_next_sentinel
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def update_sentinel_pubsub_client(host, port)
|
207
|
+
EM::Hiredis.logger.debug("update_sentinel_pubsub_client #{host}, #{port}")
|
208
|
+
@sentinel_pubsub_client.configure("redis://#{host}:#{port}")
|
209
|
+
|
210
|
+
if @sentinel_pubsub_client.instance_variable_get(:@connection)
|
211
|
+
@sentinel_pubsub_client.close_connection
|
212
|
+
EM.next_tick {
|
213
|
+
@sentinel_pubsub_client.reconnect_connection
|
214
|
+
}
|
215
|
+
else
|
216
|
+
EM::Hiredis.logger.debug("FIRST SENTINEL PUBSUB CONNECT ATTEMPT")
|
217
|
+
EM.next_tick {
|
218
|
+
@sentinel_pubsub_client.connect #first time, bc baseclient isnt expecting deferred connecting
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
222
|
+
rescue => e
|
223
|
+
EM::Hiredis.logger.warn(e)
|
224
|
+
end
|
225
|
+
|
226
|
+
def update_master_client(host, port)
|
227
|
+
EM::Hiredis.logger.debug("update_master_client #{host}, #{port}")
|
228
|
+
EM::Hiredis.logger.debug("MASTER IS UPDATING") if @is_master_updating
|
229
|
+
EM::Hiredis.logger.debug("MASTER IS ALREADY CONNECTED") if @master_client.connected?
|
230
|
+
|
231
|
+
return if @master_client.connected?
|
232
|
+
return if @is_master_updating #prevent reupdate, can be updated by discover or sentinel pubsub watching
|
233
|
+
|
234
|
+
@is_master_updating = true
|
235
|
+
|
236
|
+
@master_client.configure("redis://#{host}:#{port}") #@host, @port = host, port
|
237
|
+
|
238
|
+
if @master_client.instance_variable_get(:@connection)
|
239
|
+
@master_client.close_connection
|
240
|
+
EM.next_tick {
|
241
|
+
@master_client.reconnect_connection
|
242
|
+
}
|
243
|
+
else
|
244
|
+
EM::Hiredis.logger.debug("FIRST MASTER CONNECT ATTEMPT")
|
245
|
+
EM.next_tick {
|
246
|
+
@master_client.super_connect #first time, bc baseclient isnt expecting deferred connecting
|
247
|
+
}
|
248
|
+
end
|
249
|
+
|
250
|
+
rescue => e
|
251
|
+
EM::Hiredis.logger.warn(e)
|
252
|
+
@is_master_updating = false
|
253
|
+
queue_discover_master
|
254
|
+
end
|
255
|
+
|
256
|
+
def update_master_pubsub_client(host, port)
|
257
|
+
EM::Hiredis.logger.debug("update_master_pubsub_client #{host}, #{port}")
|
258
|
+
@master_pubsub_client.configure("redis://#{host}:#{port}")
|
259
|
+
|
260
|
+
if @master_pubsub_client.instance_variable_get(:@connection)
|
261
|
+
@master_pubsub_client.close_connection
|
262
|
+
EM.next_tick {
|
263
|
+
@master_pubsub_client.reconnect_connection
|
264
|
+
}
|
265
|
+
else
|
266
|
+
EM::Hiredis.logger.debug("FIRST MASTER PUBSUB CONNECT ATTEMPT")
|
267
|
+
EM.next_tick {
|
268
|
+
@master_pubsub_client.connect #first time, bc baseclient isnt expecting deferred connecting
|
269
|
+
}
|
270
|
+
end
|
271
|
+
rescue => e
|
272
|
+
EM::Hiredis.logger.warn(e)
|
273
|
+
end
|
274
|
+
|
275
|
+
def try_next_sentinel
|
276
|
+
#EM::Hiredis.logger.debug("try_next_sentinel")
|
277
|
+
s = @sentinels.shift
|
278
|
+
@sentinels.push s
|
279
|
+
s = @sentinels.first
|
280
|
+
update_sentinel_client(s[:host], s[:port])
|
281
|
+
end
|
282
|
+
|
283
|
+
def queue_discover_master
|
284
|
+
EM.add_timer(0.5) {
|
285
|
+
discover_master
|
286
|
+
}
|
287
|
+
end
|
288
|
+
|
289
|
+
def discover_master
|
290
|
+
EM::Hiredis.logger.debug("discover_master")
|
291
|
+
|
292
|
+
if @sentinel_client.connected?
|
293
|
+
response_deferrable = @sentinel_client.sentinel("get-master-addr-by-name", @master_name)
|
294
|
+
|
295
|
+
response_deferrable.callback do |value|
|
296
|
+
EM::Hiredis.logger.debug("discover_master callback")
|
297
|
+
master_host, master_port = value
|
298
|
+
EM::Hiredis.logger.debug("returned #{master_host} #{master_port}")
|
299
|
+
if master_host && master_port #TODO better check, seems either insufficient or unnecessary
|
300
|
+
update_master_client(master_host, master_port.to_i)
|
301
|
+
else
|
302
|
+
EM::Hiredis.logger.debug("discover_master trying again")
|
303
|
+
queue_discover_master
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
response_deferrable.errback do |e|
|
308
|
+
EM::Hiredis.logger.WARN("discover_master error")
|
309
|
+
queue_discover_master
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def refresh_sentinels_list
|
316
|
+
response_deferrable = @sentinel_client.sentinel("sentinels", @master_name)
|
317
|
+
|
318
|
+
response_deferrable.callback do |sentinels|
|
319
|
+
sentinels.each do |s|
|
320
|
+
@sentinels << {:host => s[3], :port => s[5]} #TODO will break if order changes
|
321
|
+
end
|
322
|
+
|
323
|
+
@sentinels.uniq! {|h| h.values_at(:host, :port) }
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
private
|
328
|
+
|
329
|
+
def _parse_sentinel_options(options)
|
330
|
+
opts = []
|
331
|
+
options.each do |o|
|
332
|
+
o = o[:url] if o.is_a?(Hash) && o.key?(:url)
|
333
|
+
|
334
|
+
case o
|
335
|
+
when Hash
|
336
|
+
opts << {
|
337
|
+
host: o[:host],
|
338
|
+
port: o[:port] || 26379
|
339
|
+
}
|
340
|
+
else
|
341
|
+
uri = URI.parse(o)
|
342
|
+
opts << {
|
343
|
+
:host => uri.host,
|
344
|
+
:port => uri.port || 26379
|
345
|
+
}
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
opts
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
data/lib/em-hiredis-sentinel.rb
CHANGED
@@ -1,14 +1,2 @@
|
|
1
1
|
require 'em-hiredis'
|
2
|
-
require 'em-hiredis-sentinel/
|
3
|
-
require 'em-hiredis-sentinel/base_client'
|
4
|
-
require 'em-hiredis-sentinel/pubsub_client'
|
5
|
-
|
6
|
-
module EventMachine::Hiredis
|
7
|
-
class_eval {
|
8
|
-
def self.connect_sentinel(options={})
|
9
|
-
# Should Return an EM-Hiredis client with added sentinel support
|
10
|
-
sentinel_client = EM::Hiredis::Sentinel::Client.new options
|
11
|
-
sentinel_client.redis_client
|
12
|
-
end
|
13
|
-
}
|
14
|
-
end
|
2
|
+
require 'em-hiredis-sentinel/redis_client'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-hiredis-sentinel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Schneck
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -65,12 +65,8 @@ files:
|
|
65
65
|
- README.md
|
66
66
|
- Rakefile
|
67
67
|
- em-hiredis-sentinel.gemspec
|
68
|
-
- examples/getting_started.rb
|
69
|
-
- examples/pubsub.rb
|
70
68
|
- lib/em-hiredis-sentinel.rb
|
71
|
-
- lib/em-hiredis-sentinel/
|
72
|
-
- lib/em-hiredis-sentinel/client.rb
|
73
|
-
- lib/em-hiredis-sentinel/pubsub_client.rb
|
69
|
+
- lib/em-hiredis-sentinel/redis_client.rb
|
74
70
|
- lib/em-hiredis-sentinel/version.rb
|
75
71
|
homepage: https://github.com/mobileoverlord/em-hiredis-sentinel
|
76
72
|
licenses:
|
data/examples/getting_started.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
$:.unshift(File.expand_path('../../lib', __FILE__))
|
2
|
-
require 'em-hiredis-sentinel'
|
3
|
-
require 'logger'
|
4
|
-
|
5
|
-
EM.run {
|
6
|
-
|
7
|
-
EM::Hiredis.logger = Logger.new('output.log')
|
8
|
-
|
9
|
-
|
10
|
-
redis_sentinel = EM::Hiredis::Client.new('127.0.0.1',6379,nil,nil,
|
11
|
-
:sentinels => [
|
12
|
-
{:host => '127.0.0.1', :port => 26379},
|
13
|
-
{:host => '127.0.0.1', :port => 26380},
|
14
|
-
{:host => '127.0.0.1', :port => 26381}
|
15
|
-
],
|
16
|
-
:master_name => 'mymaster').connect
|
17
|
-
|
18
|
-
EM.add_periodic_timer(1) {
|
19
|
-
puts "Connected: #{redis_sentinel.connected?}"
|
20
|
-
response_deferrable = redis_sentinel.get('foo')
|
21
|
-
response_deferrable.callback { |value|
|
22
|
-
puts value
|
23
|
-
}
|
24
|
-
response_deferrable.errback { |e|
|
25
|
-
puts e
|
26
|
-
}
|
27
|
-
}
|
28
|
-
}
|
data/examples/pubsub.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
$:.unshift(File.expand_path('../../lib', __FILE__))
|
2
|
-
require 'em-hiredis-sentinel'
|
3
|
-
require 'logger'
|
4
|
-
|
5
|
-
EM.run {
|
6
|
-
|
7
|
-
EM::Hiredis.logger = Logger.new('output.log')
|
8
|
-
|
9
|
-
|
10
|
-
redis_sentinel = EM::Hiredis::Client.new('127.0.0.1',6379,nil,nil,
|
11
|
-
:sentinels => [
|
12
|
-
{:host => '127.0.0.1', :port => 26379},
|
13
|
-
{:host => '127.0.0.1', :port => 26380},
|
14
|
-
{:host => '127.0.0.1', :port => 26381}
|
15
|
-
],
|
16
|
-
:master_name => 'mymaster').connect
|
17
|
-
|
18
|
-
redis_sentinel.pubsub.subscribe('foo') { |msg|
|
19
|
-
puts msg
|
20
|
-
}
|
21
|
-
}
|
@@ -1,129 +0,0 @@
|
|
1
|
-
module EventMachine::Hiredis
|
2
|
-
class BaseClient
|
3
|
-
class_eval {
|
4
|
-
attr_reader :sentinel_options
|
5
|
-
|
6
|
-
def initialize_with_sentinel(host = 'localhost', port = 6379, password = nil, db = nil, sentinel_options={})
|
7
|
-
|
8
|
-
initialize_without_sentinel(host,port,password,db)
|
9
|
-
if sentinel_options.nil? || sentinel_options.empty?
|
10
|
-
return
|
11
|
-
end
|
12
|
-
|
13
|
-
@sentinel_options = sentinel_options.dup
|
14
|
-
@master_name = @sentinel_options[:master_name]
|
15
|
-
@sentinels_options = _parse_sentinel_options(@sentinel_options[:sentinels])
|
16
|
-
|
17
|
-
@current_sentinel = EM::Hiredis::Client.new(@sentinels_options[0][:host],@sentinels_options[0][:port]).connect
|
18
|
-
@current_sentinel.on(:disconnected) {
|
19
|
-
EM::Hiredis.logger.info('Sentinel Failed')
|
20
|
-
try_next_sentinel
|
21
|
-
}
|
22
|
-
|
23
|
-
#discover_master
|
24
|
-
watch_sentinel
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
alias initialize_without_sentinel initialize
|
29
|
-
alias initialize initialize_with_sentinel
|
30
|
-
|
31
|
-
def watch_sentinel
|
32
|
-
pubsub = @current_sentinel.pubsub
|
33
|
-
pubsub.punsubscribe('*')
|
34
|
-
pubsub.psubscribe('*')
|
35
|
-
pubsub.on(:pmessage) { |pattern, channel, message|
|
36
|
-
next if channel != '+switch-master'
|
37
|
-
|
38
|
-
master_name, old_host, old_port, new_host, new_port = message.split(" ")
|
39
|
-
|
40
|
-
next if master_name != @master_name
|
41
|
-
EM::Hiredis.logger.info("Failover: #{old_host}:#{old_port} => #{new_host}:#{new_port}")
|
42
|
-
close_connection
|
43
|
-
@host, @port = new_host,new_port.to_i
|
44
|
-
reconnect_connection
|
45
|
-
}
|
46
|
-
end
|
47
|
-
|
48
|
-
def try_next_sentinel
|
49
|
-
|
50
|
-
sentinel_options = @sentinels_options.shift
|
51
|
-
@sentinels_options.push sentinel_options
|
52
|
-
|
53
|
-
EM::Hiredis.logger.info("Trying next sentinel: #{sentinel_options[:host]}:#{sentinel_options[:port]}")
|
54
|
-
@current_sentinel.close_connection
|
55
|
-
@current_sentinel.configure("redis://#{sentinel_options[:host]}:#{sentinel_options[:port]}")
|
56
|
-
@current_sentinel.reconnect_connection
|
57
|
-
unless @switching_sentinels
|
58
|
-
@switching_sentinels = true
|
59
|
-
@sentinel_timer = EM.add_periodic_timer(1) {
|
60
|
-
if @current_sentinel.connected?
|
61
|
-
@switching_sentinels = false
|
62
|
-
@sentinel_timer.cancel
|
63
|
-
else
|
64
|
-
try_next_sentinel
|
65
|
-
end
|
66
|
-
}
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def discover_master
|
71
|
-
response_deferrable = @current_sentinel.sentinel("get-master-addr-by-name", @master_name)
|
72
|
-
response_deferrable.callback { |value|
|
73
|
-
master_host, master_port = value
|
74
|
-
|
75
|
-
if master_host && master_port
|
76
|
-
|
77
|
-
@host, @port = master_host,master_port.to_i
|
78
|
-
reconnect_connection
|
79
|
-
refresh_sentinels_list
|
80
|
-
else
|
81
|
-
EM.next_tick {
|
82
|
-
self.discover_master
|
83
|
-
}
|
84
|
-
end
|
85
|
-
}
|
86
|
-
response_deferrable.errback { |e|
|
87
|
-
EM.next_tick {
|
88
|
-
self.discover_master
|
89
|
-
}
|
90
|
-
}
|
91
|
-
end
|
92
|
-
|
93
|
-
def refresh_sentinels_list
|
94
|
-
response_deferrable = @current_sentinel.sentinel("sentinels", @master_name)
|
95
|
-
response_deferrable.callback { |sentinels|
|
96
|
-
sentinels.each { |sentinel|
|
97
|
-
@sentinels_options << {:host => sentinel[3], :port => sentinel[5]}
|
98
|
-
@sentinels_options.uniq! {|h| h.values_at(:host, :port) }
|
99
|
-
}
|
100
|
-
}
|
101
|
-
response_deferrable.errback { |e|
|
102
|
-
try_next_sentinel
|
103
|
-
}
|
104
|
-
end
|
105
|
-
|
106
|
-
private
|
107
|
-
|
108
|
-
def _parse_sentinel_options(options)
|
109
|
-
return if options.nil?
|
110
|
-
|
111
|
-
sentinel_options = []
|
112
|
-
options.each do |opts|
|
113
|
-
opts = opts[:url] if opts.is_a?(Hash) && opts.key?(:url)
|
114
|
-
case opts
|
115
|
-
when Hash
|
116
|
-
sentinel_options << opts
|
117
|
-
else
|
118
|
-
uri = URI.parse(opts)
|
119
|
-
sentinel_options << {
|
120
|
-
:host => uri.host,
|
121
|
-
:port => uri.port
|
122
|
-
}
|
123
|
-
end
|
124
|
-
end
|
125
|
-
sentinel_options
|
126
|
-
end
|
127
|
-
}
|
128
|
-
end
|
129
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module EventMachine::Hiredis
|
2
|
-
class PubsubClient < BaseClient
|
3
|
-
class_eval {
|
4
|
-
def initialize(host='localhost', port='6379', password=nil, db=nil, sentinel_options={})
|
5
|
-
@subs, @psubs = [], []
|
6
|
-
@pubsub_defs = Hash.new { |h,k| h[k] = [] }
|
7
|
-
super
|
8
|
-
end
|
9
|
-
}
|
10
|
-
end
|
11
|
-
end
|