chasqui 0.8.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f308ee6114cf27680f344bbb770e4eeee946f467
4
- data.tar.gz: 749dbc74254f92306c8204f799a99d54d5e83017
3
+ metadata.gz: fb1a85b1db2129a864d5c04845365d0d27ee155a
4
+ data.tar.gz: 6391c76b1ab99c388d37d7db0292f524baf14f11
5
5
  SHA512:
6
- metadata.gz: a9fe9a92bba7c1be6ef419fae3f0adbb3db94010b966773b5b32d127a5e43302a6b01bb522f33b0bfd4d291fe389d2da47576a9197cd93a172fdadff875e519b
7
- data.tar.gz: f7957a3fd5ea629fcb5ac05f5cb80a1d8231385ee7dddf1f8b8dd9a349be580a3b5a1e7908be04ae21be682b9d84af4fd3433ab92b3199b02a348059c1b47803
6
+ metadata.gz: 843753b80abeea5ec7e101dd74208ff14a159f69ca15d77673bc0354e47f85e31c473278209d9a4535eaf674bc37e3522a2cdb5d786e23eea67188220bd39c7d
7
+ data.tar.gz: e4fe21a58162022da38d9a0e897879f2cf6ac73f8eb1fb54a3807952b0fda0b02ce89869d1fd5bc1af446186ec7ed3fa82635c6c6e01c9851bf65b939d446ad1
data/.travis.yml CHANGED
@@ -4,3 +4,6 @@ services:
4
4
  rvm:
5
5
  - 2.2.2
6
6
  - 1.9.3
7
+ addons:
8
+ code_climate:
9
+ repo_token: 6097f1f853daed3be96340594c273d2c5d921d860a9c21ecbc7e5f7a1ba90f43
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
1
  [![Build Status](https://travis-ci.org/jbgo/chasqui.svg?branch=master)](https://travis-ci.org/jbgo/chasqui)
2
+ [![Code Climate](https://codeclimate.com/github/jbgo/chasqui/badges/gpa.svg)](https://codeclimate.com/github/jbgo/chasqui)
3
+ [![Test Coverage](https://codeclimate.com/github/jbgo/chasqui/badges/coverage.svg)](https://codeclimate.com/github/jbgo/chasqui/coverage)
2
4
 
3
5
  # Chasqui
4
6
 
@@ -86,7 +88,7 @@ Now when you call `Chasqui.publish 'event.name', data, ...`, Chasqui will publis
86
88
 
87
89
  ```rb
88
90
  # file: otherapp/app/subscribers/user_events.rb
89
- Chasqui.subscribe queue: 'unique_queue_name_for_app', channel: 'com.example.myapp' do
91
+ Chasqui.subscribe 'com.example.myapp', queue: 'unique_queue_name_for_app' do
90
92
 
91
93
  on 'user.sign-up' do |user_id|
92
94
  user = User.find user_id
data/chasqui.gemspec CHANGED
@@ -26,4 +26,5 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "guard-rspec"
27
27
  spec.add_development_dependency "resque"
28
28
  spec.add_development_dependency "sidekiq"
29
+ spec.add_development_dependency "codeclimate-test-reporter"
29
30
  end
data/examples/full.rb CHANGED
@@ -28,7 +28,7 @@ Chasqui.configure do |config|
28
28
  end
29
29
 
30
30
  # file: transcoder/app/subscribers/video_subscriber.rb
31
- Chasqui.subscribe queue: 'transcoder.video', channel: 'com.example.admin' do
31
+ Chasqui.subscribe 'com.example.admin', queue: 'transcoder.video' do
32
32
  on 'video.upload' do |video_id|
33
33
  begin
34
34
  Transcorder.transcode video_url(video_id)
@@ -41,7 +41,7 @@ Chasqui.subscribe queue: 'transcoder.video', channel: 'com.example.admin' do
41
41
  end
42
42
 
43
43
  # file: admin/app/subscribers/video_subscriber.rb
44
- Chasqui.subscribe queue: 'admin.events', channel: 'com.example.transcoder' do
44
+ Chasqui.subscribe 'com.example.transcoder', queue: 'admin.events' do
45
45
 
46
46
  on 'transcoder.video.complete' do |video_id|
47
47
  video = Video.find video_id
@@ -1,12 +1,14 @@
1
+ require 'securerandom'
2
+
1
3
  class Chasqui::MultiBroker < Chasqui::Broker
2
4
 
3
5
  def forward_event
4
6
  event = receive or return
5
- subscribers = subscribers_for(event)
7
+ subscriptions = subscriptions_for(event)
6
8
 
7
9
  redis.multi do
8
- subscribers.each do |subscriber_id|
9
- dispatch event, subscriber_id
10
+ subscriptions.each do |subscription_id|
11
+ dispatch event, subscription_id
10
12
  end
11
13
  redis.rpop(in_progress_queue)
12
14
  end
@@ -15,11 +17,23 @@ class Chasqui::MultiBroker < Chasqui::Broker
15
17
  end
16
18
 
17
19
  def in_progress_queue
18
- to_key inbox, 'in_progress'
20
+ with_namespace inbox, 'in_progress'
19
21
  end
20
22
 
21
23
  def inbox_queue
22
- to_key inbox
24
+ with_namespace inbox
25
+ end
26
+
27
+ def build_job(queue, event)
28
+ {
29
+ class: "Chasqui::#{Chasqui.subscriber_class_name(queue)}",
30
+ args: [event],
31
+ queue: 'my-queue',
32
+ jid: SecureRandom.hex(12),
33
+ created_at: (event['created_at'] || Time.now).to_f,
34
+ enqueued_at: Time.now.to_f,
35
+ retry: !!event['retry']
36
+ }.to_json
23
37
  end
24
38
 
25
39
  private
@@ -50,8 +64,8 @@ class Chasqui::MultiBroker < Chasqui::Broker
50
64
  end
51
65
  end
52
66
 
53
- def dispatch(event, subscriber_id)
54
- backend, queue = subscriber_id.split('/', 2)
67
+ def dispatch(event, subscription_id)
68
+ backend, queue = subscription_id.split('/', 2)
55
69
  job = build_job queue, event
56
70
 
57
71
  logger.debug "dispatching event queue=#{queue} backend=#{backend} job=#{job}"
@@ -64,18 +78,12 @@ class Chasqui::MultiBroker < Chasqui::Broker
64
78
  end
65
79
  end
66
80
 
67
- def build_job(queue, event)
68
- {
69
- class: "Chasqui::#{Chasqui.subscriber_class_name(queue)}",
70
- args: [event]
71
- }.to_json
72
- end
73
-
74
- def subscribers_for(event)
75
- redis.smembers to_key('subscribers', event['channel'])
81
+ def subscriptions_for(event)
82
+ subscription_key = Chasqui.subscription_key event['channel']
83
+ redis.smembers with_namespace(subscription_key)
76
84
  end
77
85
 
78
- def to_key(*args)
86
+ def with_namespace(*args)
79
87
  ([redis_namespace] + args).join(':')
80
88
  end
81
89
 
@@ -0,0 +1,46 @@
1
+ module Chasqui
2
+ class Subscription
3
+ attr_reader :queue, :channel, :subscriber_type
4
+
5
+ def initialize(queue, channel, subscriber_type=Chasqui::Subscriber)
6
+ @queue = queue
7
+ @channel = channel
8
+ @subscriber_type = subscriber_type
9
+ end
10
+
11
+ def subscription_id
12
+ queue_name = [worker.namespace, 'queue', queue].compact.join(':')
13
+ "#{worker_backend}/#{queue_name}"
14
+ end
15
+
16
+ def subscriber
17
+ @subscriber ||= subscriber_type.new queue, channel
18
+ end
19
+
20
+ def worker
21
+ # TODO How can we store this in an instance variable without breaking things?
22
+ case worker_backend
23
+ when :resque
24
+ Chasqui::ResqueWorker.create subscriber
25
+ when :sidekiq
26
+ Chasqui::SidekiqWorker.create subscriber
27
+ else
28
+ raise ConfigurationError.new(
29
+ "Please choose a supported worker_backend. Choices: #{supported_worker_backends}")
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def worker_backend
36
+ Chasqui.config.worker_backend
37
+ end
38
+
39
+ SUPPORTED_WORKER_BACKENDS = [:resque, :sidekiq].freeze
40
+
41
+ def supported_worker_backends
42
+ SUPPORTED_WORKER_BACKENDS.join(', ')
43
+ end
44
+
45
+ end
46
+ end
@@ -1,3 +1,3 @@
1
1
  module Chasqui
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/chasqui.rb CHANGED
@@ -9,6 +9,7 @@ require "chasqui/config"
9
9
  require "chasqui/broker"
10
10
  require "chasqui/multi_broker"
11
11
  require "chasqui/subscriber"
12
+ require "chasqui/subscription"
12
13
  require "chasqui/workers/worker"
13
14
  require "chasqui/workers/resque_worker"
14
15
  require "chasqui/workers/sidekiq_worker"
@@ -28,23 +29,30 @@ module Chasqui
28
29
  end
29
30
 
30
31
  def publish(event, *args)
31
- payload = { event: event, channel: channel, data: args }
32
- redis.lpush inbox_queue, payload.to_json
32
+ redis.lpush inbox_queue, build_payload(event, *args).to_json
33
+ end
34
+
35
+ def subscribe(channel, options={}, &block)
36
+ queue = options.fetch :queue
37
+
38
+ create_subscription(queue, channel).tap do |subscription|
39
+ subscription.subscriber.evaluate(&block) if block_given?
40
+ redis.sadd subscription_key(channel), subscription.subscription_id
41
+ end
33
42
  end
34
43
 
35
- def subscribe(options={}, &block)
44
+ def unsubscribe(channel, options={}, &block)
36
45
  queue = options.fetch :queue
37
- channel = options.fetch :channel
46
+ subscription = subscriptions[queue.to_s]
38
47
 
39
- register_subscriber(queue, channel).tap do |sub|
40
- sub.evaluate(&block) if block_given?
41
- worker = create_worker(sub)
42
- redis.sadd "subscribers:#{channel}", subscriber_id(worker, queue)
48
+ if subscription
49
+ redis.srem subscription_key(channel), subscription.subscription_id
50
+ subscription.subscription_id
43
51
  end
44
52
  end
45
53
 
46
- def subscriber(queue)
47
- subscribers[queue.to_s]
54
+ def subscription(queue)
55
+ subscriptions[queue.to_s]
48
56
  end
49
57
 
50
58
  def subscriber_class_name(queue)
@@ -52,37 +60,34 @@ module Chasqui
52
60
  "Subscriber__#{queue_name_constant}".to_sym
53
61
  end
54
62
 
55
- def create_worker(subscriber)
56
- case config.worker_backend
57
- when :resque
58
- Chasqui::ResqueWorker.create subscriber
59
- when :sidekiq
60
- Chasqui::SidekiqWorker.create subscriber
61
- else
62
- raise ConfigurationError.new(
63
- "Please choose a supported worker_backend. Choices: #{supported_worker_backends}")
64
- end
63
+ def subscription_key(channel)
64
+ "subscriptions:#{channel}"
65
65
  end
66
66
 
67
67
  private
68
68
 
69
- def subscriber_id(worker, queue)
70
- queue_name = [worker.namespace, 'queue', queue].compact.join(':')
71
- "#{config.worker_backend}/#{queue_name}"
69
+ def create_subscription(queue, channel)
70
+ subscriptions[queue.to_s] ||= Subscription.new queue, channel
72
71
  end
73
72
 
74
- def register_subscriber(queue, channel)
75
- subscribers[queue.to_s] ||= Subscriber.new queue, channel
73
+ def subscriptions
74
+ @subscriptions ||= {}
76
75
  end
77
76
 
78
- def subscribers
79
- @subscribers ||= {}
80
- end
77
+ def build_payload(event, *args)
78
+ opts = extract_job_options!(*args)
79
+
80
+ payload = { event: event, channel: channel, data: args }
81
+ payload[:retry] = opts[:retry] || opts['retry'] if opts
82
+ payload[:created_at] = Time.now.to_f.to_s
81
83
 
82
- SUPPORTED_WORKER_BACKENDS = [:resque, :sidekiq].freeze
84
+ payload
85
+ end
83
86
 
84
- def supported_worker_backends
85
- SUPPORTED_WORKER_BACKENDS.join(', ')
87
+ def extract_job_options!(*args)
88
+ if args.last.kind_of?(Hash)
89
+ args.last.delete(:job_options)
90
+ end
86
91
  end
87
92
  end
88
93
  end
@@ -4,11 +4,11 @@ def log_event subscriber, args
4
4
  subscriber.redis.rpush "#{subscriber.queue}:event_log", payload
5
5
  end
6
6
 
7
- Chasqui.subscribe queue: 'app1', channel: 'integration' do
7
+ Chasqui.subscribe 'integration', queue: 'app1' do
8
8
  on('user.signup') { |*args| log_event self, args }
9
9
  end
10
10
 
11
- Chasqui.subscribe queue: 'app2', channel: 'integration' do
11
+ Chasqui.subscribe 'integration', queue: 'app2' do
12
12
  on('account.*') { |*args| log_event self, args }
13
13
  on('user.cancel') { |*args| log_event self, args }
14
14
  end
@@ -7,14 +7,15 @@ describe Chasqui::MultiBroker do
7
7
  reset_chasqui
8
8
  Chasqui.config.worker_backend = :resque
9
9
  Resque.redis.namespace = nil
10
+ allow(Time).to receive(:now).and_return(Time.now)
10
11
  end
11
12
 
12
13
  describe '#forward_event' do
13
14
  before do
14
15
  Chasqui.config.channel = 'app1'
15
- Chasqui.subscribe queue: 'queue1', channel: 'app1'
16
- Chasqui.subscribe queue: 'queue2', channel: 'app2'
17
- Chasqui.subscribe queue: 'queue3', channel: 'app1'
16
+ Chasqui.subscribe 'app1', queue: 'queue1'
17
+ Chasqui.subscribe 'app2', queue: 'queue2'
18
+ Chasqui.subscribe 'app1', queue: 'queue3'
18
19
  end
19
20
 
20
21
  it 'places the event on all subscriber queues' do
@@ -27,7 +28,7 @@ describe Chasqui::MultiBroker do
27
28
  expect(nnredis.llen('queue:queue2')).to eq(0)
28
29
  expect(nnredis.llen('queue:queue3')).to eq(1)
29
30
 
30
- event = { 'event' => 'foo.bar', 'channel' => 'app1', 'data' => ['A'] }
31
+ event = { 'event' => 'foo.bar', 'channel' => 'app1', 'data' => ['A'], 'created_at' => Time.now.to_f.to_s }
31
32
 
32
33
  job1 = JSON.parse nnredis.lpop('queue:queue1')
33
34
  expect(job1['args']).to include(event)
@@ -48,7 +49,7 @@ describe Chasqui::MultiBroker do
48
49
  job = JSON.parse nnredis.blpop('queue:queue2')[1]
49
50
  expect(job).to include('class' => 'Chasqui::Subscriber__queue2')
50
51
  expect(job).to include('args' =>
51
- [{ 'event' => 'foo.bar', 'channel' => 'app2', 'data' => ['A'] }])
52
+ [{ 'event' => 'foo.bar', 'channel' => 'app2', 'data' => ['A'], 'created_at' => Time.now.to_f.to_s }])
52
53
  end
53
54
  ensure
54
55
  thread.kill
@@ -71,7 +72,7 @@ describe Chasqui::MultiBroker do
71
72
 
72
73
  job = JSON.parse nnredis.lpop('queue:queue2')
73
74
  expect(job['args']).to include(
74
- 'event' => 'foo', 'channel' => 'app2', 'data' => ['process'])
75
+ 'event' => 'foo', 'channel' => 'app2', 'data' => ['process'], 'created_at' => Time.now.to_f.to_s)
75
76
  expect(nnredis.llen(broker.in_progress_queue)).to eq(0)
76
77
  end
77
78
 
@@ -80,4 +81,36 @@ describe Chasqui::MultiBroker do
80
81
  expect(-> { broker.forward_event }).not_to raise_error
81
82
  end
82
83
  end
84
+
85
+ describe '#build_job' do
86
+ it 'includes useful metadata' do
87
+ event = { 'event' => 'foo', 'channel' => 'bar', 'data' => [] }
88
+ job = JSON.parse broker.build_job('my-queue', event)
89
+
90
+ expect(job['class']).to eq('Chasqui::Subscriber__my_queue')
91
+ expect(job['args']).to include(event)
92
+ expect(job['queue']).to eq('my-queue')
93
+ expect(job['jid']).to match(/^[0-9a-f]{24}/i)
94
+ expect(job['created_at']).to be_within(0.01).of(Time.now.to_f)
95
+ expect(job['enqueued_at']).to be_within(0.01).of(Time.now.to_f)
96
+ expect(job['retry']).to eq(false)
97
+ end
98
+
99
+ it 'uses the event created_at time' do
100
+ created_at = (Time.now - 3).to_f
101
+ job = JSON.parse broker.build_job('my-queue', 'created_at' => created_at.to_s)
102
+ expect(job['created_at']).to eq(created_at)
103
+ end
104
+
105
+ it 'uses the event retry value' do
106
+ job = JSON.parse broker.build_job('my-queue', 'retry' => true)
107
+ expect(job['retry']).to be true
108
+
109
+ job = JSON.parse broker.build_job('my-queue', 'retry' => false)
110
+ expect(job['retry']).to be false
111
+
112
+ job = JSON.parse broker.build_job('my-queue', 'retry' => nil)
113
+ expect(job['retry']).to be false
114
+ end
115
+ end
83
116
  end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chasqui::Subscription do
4
+
5
+ def new_subscription(queue='default')
6
+ Chasqui::Subscription.new queue, 'fake-channel', FakeSubscriber
7
+ end
8
+
9
+ describe '#worker' do
10
+ it 'raises when no worker backend configured' do
11
+ Chasqui.config.worker_backend = nil
12
+ expect(-> {
13
+ new_subscription.worker
14
+ }).to raise_error(Chasqui::ConfigurationError)
15
+ end
16
+
17
+ it 'creates a resque worker' do
18
+ Chasqui.config.worker_backend = :resque
19
+ worker = new_subscription('resque-queue').worker
20
+ expect(worker.new).to be_kind_of(Chasqui::ResqueWorker)
21
+ end
22
+
23
+ if sidekiq_supported_ruby_version?
24
+ it 'creates a sidekiq worker' do
25
+ Chasqui.config.worker_backend = :sidekiq
26
+ worker = new_subscription('sidekiq-queue').worker
27
+ expect(worker.new).to be_kind_of(Chasqui::SidekiqWorker)
28
+ end
29
+ end
30
+ end
31
+
32
+ end
@@ -111,6 +111,7 @@ describe Chasqui do
111
111
  expect(event['event']).to eq('test.event')
112
112
  expect(event['channel']).to eq('__default')
113
113
  expect(event['data']).to eq(data)
114
+ expect(event['created_at'].to_f).to be_within(0.01).of(Time.now.to_f)
114
115
  end
115
116
  end
116
117
 
@@ -122,31 +123,11 @@ describe Chasqui do
122
123
  expect(event['channel']).to eq('my.app')
123
124
  expect(event['data']).to eq(['foo'])
124
125
  end
125
- end
126
-
127
- describe '.create_worker' do
128
- let(:subscriber) { j }
129
-
130
- it 'raises when no worker backend configured' do
131
- expect(-> {
132
- Chasqui.create_worker nil
133
- }).to raise_error(Chasqui::ConfigurationError)
134
- end
135
-
136
- it 'creates a resque worker' do
137
- subscriber = FakeSubscriber.new 'resque-queue', 'fake-channel'
138
- Chasqui.config.worker_backend = :resque
139
- worker = Chasqui.create_worker subscriber
140
- expect(worker.new).to be_kind_of(Chasqui::ResqueWorker)
141
- end
142
126
 
143
- if sidekiq_supported_ruby_version?
144
- it 'creates a sidekiq worker' do
145
- subscriber = FakeSubscriber.new 'sidekiq-queue', 'fake-channel'
146
- Chasqui.config.worker_backend = :sidekiq
147
- worker = Chasqui.create_worker subscriber
148
- expect(worker.new).to be_kind_of(Chasqui::SidekiqWorker)
149
- end
127
+ it 'supports retries' do
128
+ Chasqui.publish 'test.event', :foo, :bar, foo: 'bar', job_options: { retry: true }
129
+ event = JSON.load Chasqui.redis.rpop('inbox')
130
+ expect(event['retry']).to eq(true)
150
131
  end
151
132
  end
152
133
 
@@ -160,18 +141,18 @@ describe Chasqui do
160
141
  before { Resque.redis.namespace = 'blah' }
161
142
 
162
143
  it 'creates subscriptions using the appropriate redis namespace' do
163
- sub1 = Chasqui.subscribe queue: 'app1-queue', channel: 'com.example.admin'
164
- sub2 = Chasqui.subscribe queue: 'app2-queue', channel: 'com.example.admin'
165
- sub3 = Chasqui.subscribe queue: 'app1-queue', channel: 'com.example.video'
144
+ sub1 = Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
145
+ sub2 = Chasqui.subscribe 'com.example.admin', queue: 'app2-queue'
146
+ sub3 = Chasqui.subscribe 'com.example.video', queue: 'app1-queue'
166
147
 
167
- queues = Chasqui.redis.smembers "subscribers:com.example.admin"
148
+ queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.admin")
168
149
  expect(queues.sort).to eq(['resque/blah:queue:app1-queue', 'resque/blah:queue:app2-queue'])
169
150
 
170
- queues = Chasqui.redis.smembers "subscribers:com.example.video"
151
+ queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.video")
171
152
  expect(queues).to eq(['resque/blah:queue:app1-queue'])
172
153
 
173
- expect(Chasqui.subscriber('app1-queue')).to eq(sub1)
174
- expect(Chasqui.subscriber('app2-queue')).to eq(sub2)
154
+ expect(Chasqui.subscription('app1-queue')).to eq(sub1)
155
+ expect(Chasqui.subscription('app2-queue')).to eq(sub2)
175
156
  expect(sub1).to eq(sub3)
176
157
  end
177
158
  end
@@ -183,32 +164,55 @@ describe Chasqui do
183
164
  end
184
165
 
185
166
  it 'creates subscriptions using the appropriate redis namespace' do
186
- Chasqui.subscribe queue: 'app1-queue', channel: 'com.example.admin'
187
- queues = Chasqui.redis.smembers "subscribers:com.example.admin"
167
+ Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
168
+ queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.admin")
188
169
  expect(queues.sort).to eq(['sidekiq/queue:app1-queue'])
189
170
 
190
171
  Sidekiq.redis = { url: redis.client.options[:url], namespace: 'foobar' }
191
- Chasqui.subscribe queue: 'app2-queue', channel: 'com.example.video'
192
- queues = Chasqui.redis.smembers "subscribers:com.example.video"
172
+ Chasqui.subscribe 'com.example.video', queue: 'app2-queue'
173
+ queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.video")
193
174
  expect(queues.sort).to eq(['sidekiq/foobar:queue:app2-queue'])
194
175
  end
195
176
  end
196
177
  end
197
178
 
198
- it 'returns a subscriber' do
199
- subscriber = Chasqui.subscribe queue: 'app1-queue', channel: 'com.example.admin'
200
- expect(subscriber).to be_kind_of(Chasqui::Subscriber)
179
+ it 'returns a subscription' do
180
+ subscription = Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
181
+ expect(subscription.subscriber).to be_kind_of(Chasqui::Subscriber)
201
182
  end
202
183
 
203
184
  it 'yields a subscriber configuration context' do
204
185
  $context = nil
205
- Chasqui.subscribe queue: 'foo', channel: 'bar' do
186
+ Chasqui.subscribe 'bar', queue: 'foo' do
206
187
  $context = self
207
188
  end
208
189
  expect($context).to be_kind_of(Chasqui::Subscriber)
209
190
  end
210
191
  end
211
192
 
193
+ describe '.unsubscribe' do
194
+ before do
195
+ reset_chasqui
196
+ Chasqui.config.worker_backend = :resque
197
+ Resque.redis.namespace = 'ns0'
198
+ Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
199
+ Chasqui.subscribe 'com.example.admin', queue: 'app2-queue'
200
+ Chasqui.subscribe 'com.example.video', queue: 'app1-queue'
201
+ end
202
+
203
+ it 'removes the subscription' do
204
+ subscription_id = Chasqui.unsubscribe 'com.example.admin', queue: 'app1-queue'
205
+ expect(subscription_id).to eq('resque/ns0:queue:app1-queue')
206
+ expect(redis.smembers(Chasqui.subscription_key 'com.example.admin').sort).to eq(['resque/ns0:queue:app2-queue'])
207
+ expect(redis.smembers(Chasqui.subscription_key 'com.example.video').sort).to eq(['resque/ns0:queue:app1-queue'])
208
+ end
209
+
210
+ it 'returns nil for unknown subscriptions' do
211
+ subscription_id = Chasqui.unsubscribe 'unknown', queue: 'unknown'
212
+ expect(subscription_id).to be nil
213
+ end
214
+ end
215
+
212
216
  describe '.subscriber_class_name' do
213
217
  it 'transforms queue name into a subscribe class name' do
214
218
  expect(Chasqui.subscriber_class_name('my-queue')).to eq(:Subscriber__my_queue)
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
1
4
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
5
  require 'chasqui'
3
6
  require 'resque'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chasqui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Bach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-01 00:00:00.000000000 Z
11
+ date: 2015-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: codeclimate-test-reporter
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  description:
126
140
  email:
127
141
  - jordan@opensolitude.com
@@ -147,6 +161,7 @@ files:
147
161
  - lib/chasqui/config.rb
148
162
  - lib/chasqui/multi_broker.rb
149
163
  - lib/chasqui/subscriber.rb
164
+ - lib/chasqui/subscription.rb
150
165
  - lib/chasqui/version.rb
151
166
  - lib/chasqui/workers/resque_worker.rb
152
167
  - lib/chasqui/workers/sidekiq_worker.rb
@@ -162,6 +177,7 @@ files:
162
177
  - spec/lib/chasqui/config_spec.rb
163
178
  - spec/lib/chasqui/multi_broker_spec.rb
164
179
  - spec/lib/chasqui/subscriber_spec.rb
180
+ - spec/lib/chasqui/subscription_spec.rb
165
181
  - spec/lib/chasqui/workers/resque_worker_spec.rb
166
182
  - spec/lib/chasqui/workers/sidekiq_worker_spec.rb
167
183
  - spec/lib/chasqui_spec.rb
@@ -208,6 +224,7 @@ test_files:
208
224
  - spec/lib/chasqui/config_spec.rb
209
225
  - spec/lib/chasqui/multi_broker_spec.rb
210
226
  - spec/lib/chasqui/subscriber_spec.rb
227
+ - spec/lib/chasqui/subscription_spec.rb
211
228
  - spec/lib/chasqui/workers/resque_worker_spec.rb
212
229
  - spec/lib/chasqui/workers/sidekiq_worker_spec.rb
213
230
  - spec/lib/chasqui_spec.rb
@@ -216,3 +233,4 @@ test_files:
216
233
  - spec/support/fake_logger.rb
217
234
  - spec/support/fake_subscriber.rb
218
235
  - spec/support/sidekiq_compatibility_check.rb
236
+ has_rdoc: