pubsubstub 0.0.15 → 0.1.0.beta1
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/.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
|