backrub 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/Rakefile +1 -1
- data/backrub.gemspec +1 -1
- data/lib/backrub.rb +13 -55
- data/lib/backrub/store/base.rb +17 -0
- data/lib/backrub/store/redis.rb +46 -0
- data/lib/backrub/version.rb +3 -0
- data/test/backrub/store/redis_test.rb +50 -0
- data/test/backrub_test.rb +21 -34
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d42c9e5402d9150f81a77e3d2359c563db3de03
|
4
|
+
data.tar.gz: dee8d063247b1a74db02a20807a814f24ced01c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77cc4d20ba3e9b1ff5c1dfadef7c25e601d56aa95badd7390573f8708f5b868f4222cc2d81ee78e24365430a8df07817246ca40a58ee554abf813d75ed798db3
|
7
|
+
data.tar.gz: 2b55a4e20b6e55dad15a7898ac0d5e0075201a4e5dc673793c02de112547c812166df3e4acac6ec97153f782ac1b516d04c1ac4bbc6a500e32373f146281cd5c
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
data/backrub.gemspec
CHANGED
data/lib/backrub.rb
CHANGED
@@ -1,68 +1,26 @@
|
|
1
|
-
require '
|
1
|
+
require 'backrub/store/base'
|
2
|
+
require 'backrub/store/redis'
|
3
|
+
require 'backrub/version'
|
2
4
|
|
3
5
|
module Backrub
|
4
|
-
VERSION = "1.0.0"
|
5
|
-
|
6
|
-
DEFAULT_BACKLOG_SIZE = 100
|
7
|
-
|
8
6
|
extend self
|
9
7
|
|
10
|
-
attr_writer :
|
11
|
-
|
12
|
-
|
13
|
-
@redis_config ||= {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def redis
|
17
|
-
@redis ||= new_redis
|
8
|
+
attr_writer :store
|
9
|
+
def store
|
10
|
+
@store ||= Backrub::Store::Redis.new
|
18
11
|
end
|
19
12
|
|
20
|
-
def subscribe(
|
21
|
-
|
22
|
-
|
23
|
-
if channels.count == 1 && channels.first.is_a?(Hash)
|
24
|
-
hash = channels.first
|
25
|
-
|
26
|
-
hash.each do |channel, offset|
|
27
|
-
if offset > 0
|
28
|
-
backlog = redis.lrange(channel, 0, offset - 1)
|
29
|
-
|
30
|
-
backlog.reverse_each do |message|
|
31
|
-
yield channel.to_s, message
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
channels = hash.keys
|
37
|
-
end
|
38
|
-
|
39
|
-
begin
|
40
|
-
# Open a new connection because the connection blocks, causing other threads to be unable to use it
|
41
|
-
local_redis = new_redis
|
42
|
-
local_redis.subscribe(*channels) do |on|
|
43
|
-
on.message do |channel, message|
|
44
|
-
yield channel, message
|
45
|
-
end
|
46
|
-
end
|
47
|
-
ensure
|
48
|
-
local_redis.quit
|
13
|
+
def subscribe(channels_with_backlog, &block)
|
14
|
+
channels_with_backlog.each do |channel, count|
|
15
|
+
store.backlog(channel.to_s, count.to_i, &block) unless count.zero?
|
49
16
|
end
|
50
|
-
end
|
51
17
|
|
52
|
-
|
53
|
-
redis.multi do
|
54
|
-
redis.publish(channel, message)
|
55
|
-
redis.lpush(channel, message)
|
56
|
-
redis.ltrim(channel, 0, backlog_size - 1)
|
57
|
-
end
|
58
|
-
end
|
18
|
+
channels = channels_with_backlog.keys.map(&:to_s)
|
59
19
|
|
60
|
-
|
61
|
-
@backlog_size || DEFAULT_BACKLOG_SIZE
|
20
|
+
store.subscribe(*channels, &block)
|
62
21
|
end
|
63
22
|
|
64
|
-
|
65
|
-
|
66
|
-
Redis.new(redis_config)
|
23
|
+
def publish(channel, message)
|
24
|
+
store.publish(channel, message)
|
67
25
|
end
|
68
26
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Backrub
|
2
|
+
module Store
|
3
|
+
class Base
|
4
|
+
def backlog(channel, count)
|
5
|
+
raise NotImplementedError
|
6
|
+
end
|
7
|
+
|
8
|
+
def publish(channel, message)
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
def subscribe(*channel)
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module Backrub
|
4
|
+
module Store
|
5
|
+
class Redis < Base
|
6
|
+
attr_reader :config, :backlog_size
|
7
|
+
|
8
|
+
def initialize(config={}, backlog_size=100)
|
9
|
+
@config = config
|
10
|
+
@backlog_size = backlog_size
|
11
|
+
end
|
12
|
+
|
13
|
+
def redis
|
14
|
+
@redis ||= ::Redis.new(config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def backlog(channel, count)
|
18
|
+
backlog = redis.lrange(channel, 0, count - 1)
|
19
|
+
|
20
|
+
backlog.reverse_each do |message|
|
21
|
+
yield channel, message
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def publish(channel, message)
|
26
|
+
redis.multi do
|
27
|
+
redis.publish(channel, message)
|
28
|
+
redis.lpush(channel, message)
|
29
|
+
redis.ltrim(channel, 0, backlog_size - 1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def subscribe(*channels)
|
34
|
+
# Open a new connection because the connection blocks, causing other threads to be unable to use it
|
35
|
+
local_redis = ::Redis.new(config)
|
36
|
+
local_redis.subscribe(*channels) do |on|
|
37
|
+
on.message do |channel, message|
|
38
|
+
yield channel, message
|
39
|
+
end
|
40
|
+
end
|
41
|
+
ensure
|
42
|
+
local_redis.quit
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BackrubRedisTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@backlog = 20
|
6
|
+
@config = {}
|
7
|
+
@store = Backrub::Store::Redis.new(@config, @backlog)
|
8
|
+
@redis = @store.redis
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_backlog
|
12
|
+
backlog = 20.times.map {|n| "a" * (n+1)}
|
13
|
+
channel = "test"
|
14
|
+
count = 5
|
15
|
+
@redis.expects(:lrange).with(channel, 0, count - 1).returns(backlog[0...count])
|
16
|
+
|
17
|
+
received_backlog = []
|
18
|
+
|
19
|
+
@store.backlog(channel, count) do |channel, message|
|
20
|
+
received_backlog << message
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_equal backlog[0...count].reverse, received_backlog
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_publishing
|
27
|
+
channel = "test"
|
28
|
+
message = "data"
|
29
|
+
@redis.expects(:publish).with(channel, message)
|
30
|
+
@redis.expects(:lpush).with(channel, message)
|
31
|
+
@redis.expects(:ltrim).with(channel, 0, @backlog - 1)
|
32
|
+
|
33
|
+
@store.publish(channel, message)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_subscribing
|
37
|
+
test_messages = [["test", "data"], ["test2", "data2"]]
|
38
|
+
|
39
|
+
mock_redis = mock()
|
40
|
+
mock_message_handler = mock()
|
41
|
+
mock_message_handler.expects(:message).multiple_yields(*test_messages)
|
42
|
+
mock_redis.expects(:subscribe).with("test", "test2").yields(mock_message_handler)
|
43
|
+
mock_redis.expects(:quit)
|
44
|
+
::Redis.expects(:new).returns(mock_redis)
|
45
|
+
|
46
|
+
@store.subscribe("test", "test2") do |channel, message|
|
47
|
+
assert_equal test_messages.shift, [channel, message]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/test/backrub_test.rb
CHANGED
@@ -1,52 +1,39 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class BackrubTest < MiniTest::Unit::TestCase
|
4
|
-
|
5
|
-
channel = "test"
|
6
|
-
message = "data"
|
7
|
-
Backrub.redis.expects(:publish).with(channel, message)
|
8
|
-
Backrub.redis.expects(:lpush).with(channel, message)
|
9
|
-
Backrub.redis.expects(:ltrim).with(channel, 0, Backrub::DEFAULT_BACKLOG_SIZE - 1)
|
10
|
-
|
11
|
-
Backrub.publish(channel, message)
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_subscribing
|
15
|
-
fake_redis = mock()
|
16
|
-
subscribe_object = mock()
|
17
|
-
subscribe_object.expects(:message).yields(["test", "data"])
|
18
|
-
fake_redis.expects(:subscribe).with("test").yields(subscribe_object)
|
19
|
-
fake_redis.expects(:quit)
|
4
|
+
class MockStore < Backrub::Store::Base
|
20
5
|
|
21
|
-
|
6
|
+
end
|
22
7
|
|
23
|
-
|
24
|
-
|
25
|
-
assert_equal "data", message
|
26
|
-
end
|
8
|
+
def setup
|
9
|
+
Backrub.store = MockStore.new
|
27
10
|
end
|
28
11
|
|
29
|
-
def
|
12
|
+
def test_subscribing
|
30
13
|
channels = {
|
31
14
|
first_channel: 0,
|
32
15
|
second_channel: 2
|
33
16
|
}
|
34
|
-
|
35
|
-
Backrub.redis.expects(:lrange).with(:second_channel, 0, 1).returns(second_channel_data.dup)
|
36
|
-
second_channel_data.unshift("third_bit")
|
37
|
-
|
38
|
-
fake_redis = mock()
|
39
|
-
subscribe_object = mock()
|
40
|
-
subscribe_object.expects(:message).yields(["second_channel", "third_bit"])
|
17
|
+
Backrub.store.expects(:backlog).with("second_channel", 2).multiple_yields(["second_channel", "first_bit"], ["second_channel", "second_bit"])
|
41
18
|
|
42
|
-
|
43
|
-
|
19
|
+
expected_data = [
|
20
|
+
["second_channel", "first_bit"],
|
21
|
+
["second_channel", "second_bit"],
|
22
|
+
["first_channel", "third_bit"],
|
23
|
+
]
|
44
24
|
|
45
|
-
Backrub.expects(:
|
25
|
+
Backrub.store.expects(:subscribe).with("first_channel", "second_channel").yields(["first_channel", "third_bit"])
|
46
26
|
|
27
|
+
data = []
|
47
28
|
Backrub.subscribe(channels) do |channel, message|
|
48
|
-
|
49
|
-
assert_equal second_channel_data.pop, message
|
29
|
+
data << [channel, message]
|
50
30
|
end
|
31
|
+
|
32
|
+
assert_equal expected_data, data
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_publishing
|
36
|
+
Backrub.store.expects(:publish).with("test", "data")
|
37
|
+
Backrub.publish("test", "data")
|
51
38
|
end
|
52
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backrub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bouke van der Bijl
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -95,6 +95,10 @@ files:
|
|
95
95
|
- Rakefile
|
96
96
|
- backrub.gemspec
|
97
97
|
- lib/backrub.rb
|
98
|
+
- lib/backrub/store/base.rb
|
99
|
+
- lib/backrub/store/redis.rb
|
100
|
+
- lib/backrub/version.rb
|
101
|
+
- test/backrub/store/redis_test.rb
|
98
102
|
- test/backrub_test.rb
|
99
103
|
- test/test_helper.rb
|
100
104
|
homepage: ''
|
@@ -122,6 +126,7 @@ signing_key:
|
|
122
126
|
specification_version: 4
|
123
127
|
summary: Redis-based pubsub system with a backlog
|
124
128
|
test_files:
|
129
|
+
- test/backrub/store/redis_test.rb
|
125
130
|
- test/backrub_test.rb
|
126
131
|
- test/test_helper.rb
|
127
132
|
has_rdoc:
|