pubsubstub 0.0.15 → 0.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -1
- data/Gemfile +8 -0
- data/README.md +10 -4
- data/Rakefile +6 -1
- data/bin/console +16 -0
- data/bin/server +3 -0
- data/example/Gemfile +1 -1
- data/example/config.ru +2 -0
- data/example/puma_config.rb +19 -0
- data/lib/pubsubstub.rb +65 -4
- data/lib/pubsubstub/action.rb +0 -10
- data/lib/pubsubstub/channel.rb +21 -35
- data/lib/pubsubstub/event.rb +10 -6
- data/lib/pubsubstub/logging.rb +15 -0
- data/lib/pubsubstub/publish_action.rb +1 -2
- data/lib/pubsubstub/stream_action.rb +74 -40
- data/lib/pubsubstub/subscriber.rb +88 -0
- data/lib/pubsubstub/subscription.rb +62 -0
- data/lib/pubsubstub/version.rb +1 -1
- data/pubsubstub.gemspec +0 -9
- data/spec/channel_spec.rb +21 -75
- data/spec/publish_action_spec.rb +13 -0
- data/spec/spec_helper.rb +21 -3
- data/spec/stream_action_spec.rb +34 -97
- data/spec/subscriber_spec.rb +45 -0
- data/spec/subscription_spec.rb +70 -0
- data/spec/support/http_helpers.rb +52 -0
- data/spec/support/threading_matchers.rb +58 -0
- metadata +24 -135
- data/lib/pubsubstub/redis_pub_sub.rb +0 -73
- data/spec/redis_pub_sub_spec.rb +0 -121
@@ -1,73 +0,0 @@
|
|
1
|
-
module Pubsubstub
|
2
|
-
class RedisPubSub
|
3
|
-
EVENT_SCORE_THRESHOLD = 1000
|
4
|
-
EXPIRE_THRESHOLD = 24 * 60 * 60
|
5
|
-
|
6
|
-
def initialize(channel_name)
|
7
|
-
@channel_name = channel_name
|
8
|
-
end
|
9
|
-
|
10
|
-
def subscribe(callback)
|
11
|
-
self.class.sub.subscribe(key('pubsub'), callback)
|
12
|
-
end
|
13
|
-
|
14
|
-
def unsubscribe(callback)
|
15
|
-
self.class.sub.unsubscribe_proc(key('pubsub'), callback)
|
16
|
-
end
|
17
|
-
|
18
|
-
def publish(event)
|
19
|
-
self.class.publish(@channel_name, event)
|
20
|
-
end
|
21
|
-
|
22
|
-
def scrollback(since_event_id)
|
23
|
-
redis_scrollback(since_event_id) do |json|
|
24
|
-
yield Pubsubstub::Event.from_json(json)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def redis_scrollback(since_event_id, &block)
|
31
|
-
args = [key('scrollback'), "(#{since_event_id.to_i}", '+inf']
|
32
|
-
if EventMachine.reactor_running?
|
33
|
-
self.class.nonblocking_redis.zrangebyscore(*args) do |events|
|
34
|
-
events.each(&block)
|
35
|
-
end
|
36
|
-
else
|
37
|
-
self.class.blocking_redis.zrangebyscore(*args).each(&block)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def key(purpose)
|
42
|
-
[@channel_name, purpose].join(".")
|
43
|
-
end
|
44
|
-
|
45
|
-
class << self
|
46
|
-
def publish(channel_name, event)
|
47
|
-
scrollback = "#{channel_name}.scrollback"
|
48
|
-
blocking_redis.pipelined do
|
49
|
-
blocking_redis.publish("#{channel_name}.pubsub", event.to_json)
|
50
|
-
blocking_redis.zadd(scrollback, event.id, event.to_json)
|
51
|
-
blocking_redis.zremrangebyrank(scrollback, 0, -EVENT_SCORE_THRESHOLD)
|
52
|
-
blocking_redis.expire(scrollback, EXPIRE_THRESHOLD)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def sub
|
57
|
-
@sub ||= nonblocking_redis.pubsub
|
58
|
-
end
|
59
|
-
|
60
|
-
def blocking_redis
|
61
|
-
@blocking_redis ||= Redis.new(url: redis_url)
|
62
|
-
end
|
63
|
-
|
64
|
-
def nonblocking_redis
|
65
|
-
@nonblocking_redis ||= EM::Hiredis.connect(redis_url)
|
66
|
-
end
|
67
|
-
|
68
|
-
def redis_url
|
69
|
-
Pubsubstub.redis_url || ENV['REDIS_URL'] || "redis://localhost:6379/0"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
data/spec/redis_pub_sub_spec.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Pubsubstub::RedisPubSub do
|
4
|
-
|
5
|
-
context "class singleton methods" do
|
6
|
-
subject { Pubsubstub::RedisPubSub }
|
7
|
-
|
8
|
-
describe "#publish" do
|
9
|
-
let(:redis) { double('redis') }
|
10
|
-
let(:event) { double('Event', to_json: "event_data", id: 1234) }
|
11
|
-
before {
|
12
|
-
allow(redis).to receive(:pipelined).and_yield
|
13
|
-
}
|
14
|
-
|
15
|
-
it "publishes the event to a redis channel and adds it to the scrollback" do
|
16
|
-
allow(subject).to receive(:blocking_redis) { redis }
|
17
|
-
expect(redis).to receive(:publish).with("test.pubsub", event.to_json)
|
18
|
-
expect(redis).to receive(:zadd).with("test.scrollback", event.id, event.to_json)
|
19
|
-
expect(redis).to receive(:zremrangebyrank).with("test.scrollback", 0, -1000)
|
20
|
-
expect(redis).to receive(:expire).with("test.scrollback", Pubsubstub::RedisPubSub::EXPIRE_THRESHOLD)
|
21
|
-
subject.publish("test", event)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "truncates the scrollback" do
|
25
|
-
count = Pubsubstub::RedisPubSub::EVENT_SCORE_THRESHOLD
|
26
|
-
(1...count).each do |id|
|
27
|
-
event = double(to_json: "event_data #{id}", id: id)
|
28
|
-
subject.publish('test', event)
|
29
|
-
end
|
30
|
-
expect(subject.blocking_redis.zcard("test.scrollback")).to eq(count - 1)
|
31
|
-
|
32
|
-
event = double(to_json: "event_data N", id: count)
|
33
|
-
subject.publish('test', event)
|
34
|
-
expect(subject.blocking_redis.zcard("test.scrollback")).to eq(count - 1)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "#redis_url" do
|
39
|
-
it "uses the fallback url fallback chain" do
|
40
|
-
Pubsubstub.redis_url = "redis://localhost:6379/1"
|
41
|
-
expect(Pubsubstub::RedisPubSub.redis_url).to eq("redis://localhost:6379/1")
|
42
|
-
|
43
|
-
Pubsubstub.redis_url = nil
|
44
|
-
ENV['REDIS_URL'] = "redis://localhost:6379/2"
|
45
|
-
expect(Pubsubstub::RedisPubSub.redis_url).to eq("redis://localhost:6379/2")
|
46
|
-
|
47
|
-
Pubsubstub::RedisPubSub.instance_variable_set(:@blocking_redis, nil)
|
48
|
-
ENV['REDIS_URL'] = nil
|
49
|
-
expect(Pubsubstub::RedisPubSub.redis_url).to eq("redis://localhost:6379/0")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context "pubsub" do
|
55
|
-
subject { Pubsubstub::RedisPubSub.new("test") }
|
56
|
-
let(:pubsub) { double('redis pubsub') }
|
57
|
-
let(:callback) { ->{} }
|
58
|
-
|
59
|
-
describe "#subscribe" do
|
60
|
-
before {
|
61
|
-
allow(subject.class).to receive(:sub) { pubsub }
|
62
|
-
}
|
63
|
-
|
64
|
-
it "creates a redis sub with the callback" do
|
65
|
-
expect(pubsub).to receive(:subscribe).with("test.pubsub", callback)
|
66
|
-
subject.subscribe(callback)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe "#unsubscribe" do
|
71
|
-
before {
|
72
|
-
allow(subject.class).to receive(:sub) { pubsub }
|
73
|
-
}
|
74
|
-
|
75
|
-
it "creates a redis sub with the callback" do
|
76
|
-
expect(pubsub).to receive(:unsubscribe_proc).with("test.pubsub", callback)
|
77
|
-
subject.unsubscribe(callback)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe "#publish" do
|
82
|
-
let(:event) { Pubsubstub::Event.new("toto") }
|
83
|
-
it "delegates to RedisPubSub.publish" do
|
84
|
-
expect(Pubsubstub::RedisPubSub).to receive(:publish).with("test", event)
|
85
|
-
subject.publish(event)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe "#scrollback" do
|
91
|
-
subject { Pubsubstub::RedisPubSub.new("test") }
|
92
|
-
|
93
|
-
let(:event1) { Pubsubstub::Event.new("toto", id: 1235) }
|
94
|
-
let(:event2) { Pubsubstub::Event.new("toto", id: 1236) }
|
95
|
-
|
96
|
-
describe "without EventMachine" do
|
97
|
-
it "yields the events in the scrollback" do
|
98
|
-
redis = double('redis')
|
99
|
-
expect(redis).to receive(:zrangebyscore)
|
100
|
-
.with('test.scrollback', '(1234', '+inf')
|
101
|
-
.and_return([event1.to_json, event2.to_json])
|
102
|
-
|
103
|
-
expect(Pubsubstub::RedisPubSub).to receive(:blocking_redis).and_return(redis)
|
104
|
-
expect { |block| subject.scrollback(1234, &block) }.to yield_successive_args(event1, event2)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
describe "with EventMachine" do
|
109
|
-
it "yields the events in the scrollback" do
|
110
|
-
allow(EventMachine).to receive(:reactor_running?).and_return(true)
|
111
|
-
redis = double('redis')
|
112
|
-
expect(redis).to receive(:zrangebyscore)
|
113
|
-
.with('test.scrollback', '(1234', '+inf')
|
114
|
-
.and_yield([event1.to_json, event2.to_json])
|
115
|
-
|
116
|
-
expect(Pubsubstub::RedisPubSub).to receive(:nonblocking_redis).and_return(redis)
|
117
|
-
expect { |block| subject.scrollback(1234, &block) }.to yield_successive_args(event1, event2)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|