chasqui 0.9.2 → 0.9.3

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: 12b2617a27713b277443f047d9c67da2c7e18433
4
- data.tar.gz: ee175fd077ade18393fccc35bbb2773ef23247dd
3
+ metadata.gz: c7b83716114be3ede50a3559cb742d776cdecd1f
4
+ data.tar.gz: df453dfaa501a592ddc6b3c650fcae09a9343123
5
5
  SHA512:
6
- metadata.gz: eb442618ee0aef74d6898a7effeb6d28eebb164806013a8621b8f0b622e44935d85c27cc187c04acf54597af83f516aa9e7e3fbf44c1d417b2d477135031165e
7
- data.tar.gz: 30fe8a703c8fd84b780c7cbde3c702aabd64ed93ad0be632a7deac93261636fe9199de4f092ebe41c0d9b0a85d9e282e22260008ab28b59fe00b51e1fc83d46f
6
+ metadata.gz: 91b367f3cd65f4bceffd73ebbdd6ef9d9af344741d797ebb8909d7b372c8246c99cee930b3b0a3cf09f316cbd48e84f11f82cfcd16f2251acdaa63c089fba7be
7
+ data.tar.gz: 420990d6feaa68f81d4db1ec6076a0c2b8fa2e5bd137dcf41a222d89734fa8e560e5d2e8cbb07a455d22a827e020c43c744f886e78a6f17e3f60c9e255f73f55
data/README.md CHANGED
@@ -9,131 +9,111 @@ messaging pattern for service oriented architectures.
9
9
  Chasqui delivers messages to subscribers in a Resque-compatible format. If you are already
10
10
  using Resque and/or Sidekiq, Chasqui will make a wonderful companion to your architecture.
11
11
 
12
- ## Why do you need Chasqui?
12
+ ## Installation
13
13
 
14
- * To reduce coupling between applications
15
- * To process, monitor, and retry messages idependent of request cycles
14
+ Add this line to your application's Gemfile:
16
15
 
17
- ## Design
16
+ gem 'chasqui'
18
17
 
19
- Chasqui is designed with reliability in mind.
20
- Failure is expected and planned for in the design.
18
+ And then execute:
21
19
 
22
- Chasqui uses Redis to create persistent queues. Chasqui does not use the Redis Pub/Sub feature
23
- because it cannot ensure delivery of messages, especially when subscribers are not running.
20
+ $ bundle
24
21
 
25
- Chasqui consists of two components, a client and a server.
26
- The client provides a simple interface for publishing messages. The client places messages
27
- on a persistent queue, called an inbox, where they wait for further processing.
28
- The server reads messages from the inbox and places them on the queues of each subscriber.
29
- The server will create queues for subscribers if the queues do not exist.
22
+ Or install it yourself as:
30
23
 
31
- The advantage of this design is that messages are not lost when the chasqui server or the
32
- chasqui subscribers are not running.
24
+ $ gem install chasqui
33
25
 
34
- ## Is Chasqui the best choice for you?
26
+ ## Dependencies
35
27
 
36
- Chasqui is perfect for you if your current architecture meets all of the following criteria
37
- listed below.
28
+ Chasqui uses Redis to queue events and manage subscriptions. You can install
29
+ redis with your favorite package manager, such as homebrew, yum, or apt, or if
30
+ you prefer, you can run `vagrant up` to run Redis in a virtual machine.
38
31
 
39
- 1. You have a service oriented architecture of some kind.
40
- 2. You primarily use resque and/or sidekiq to process jobs already.
41
- 3. You want a simple Pub/Sub solution with minimal setup and maintenance.
42
- 4. Your organization or traffic volume is not high enough to warrant a more complex solution.
32
+ ## Quick Start
43
33
 
44
- If any of the above are not true for you, you may want to consider other available solutions.
45
- This website maintains a list of alternatives for you to consider: http://queues.io/
34
+ Chasqui consistents of two components - a client and a broker. The broker's
35
+ responsibility is to forward published events to registered subscribers. The
36
+ client can both publish events and register subscribers.
46
37
 
47
- If Chasqui is not right for you, then please use another solution. I designed Chasqui to
48
- solve a specific problem for a particular scale and company size.
38
+ ### Start the broker
49
39
 
50
- ## Installation
40
+ chasqui -r redis://localhost:6379/0 -q my-app
51
41
 
52
- Add this line to your application's Gemfile:
42
+ Your broker must use the same redis connection as your sidekiq (or resque)
43
+ workers. For a list of available broker options, run `chasqui --help`.
53
44
 
54
- ```ruby
55
- gem 'chasqui'
56
- ```
45
+ ### Publish events
57
46
 
58
- And then execute:
47
+ Publishing events is simple.
59
48
 
60
- $ bundle
49
+ # file: publisher.rb
50
+ require 'chasqui'
51
+ Chasqui.publish 'user.sign-up', 'Luke Skywalker'
52
+ Chasqui.publish 'user.cancel', 'Dart Vader', 'invalid use of the force'
61
53
 
62
- Or install it yourself as:
54
+ Be sure to run the publisher, broker, and subscribers in separate terminal
55
+ windows.
63
56
 
64
- $ gem install chasqui
57
+ ruby publisher.rb
65
58
 
66
- ## Publishing events
59
+ ### Subscribe to events
67
60
 
68
- Publishing events is simple.
61
+ Subscribing to events is also simple. The following example tells chasqui to
62
+ forward events to the subscriber's 'my-app' queue, for which chasqui will
63
+ generate the appropriate worker class. Within the subscriber block, you define
64
+ one or more `on` blocks in which you place your application logic for handling
65
+ an event.
69
66
 
70
- ```rb
71
- Chasqui.publish 'user.sign-up', user_id
72
- ```
67
+ # file: subscriber1.rb
68
+ require 'chasqui'
73
69
 
74
- To prevent conflicts with other applications, you can choose a unique channel for your events.
70
+ Chasqui.subscribe queue: 'my-app' do
75
71
 
76
- ```rb
77
- # config/initializers/chasqui.rb
78
- Chasqui.configure do |config|
79
- config.channel = 'com.example.myapp'
80
- end
81
- ```
72
+ on 'user.sign-up' do |user_id|
73
+ # do something when the user signs up
74
+ end
82
75
 
83
- Now when you call `Chasqui.publish 'event.name', data, ...`, Chasqui will publish the event
84
- `com.example.myapp.user.sign-up`.
76
+ on 'user.cancel' do |user_id, reason|
77
+ # do something else when user cancels
78
+ end
85
79
 
86
- ## Subscribing to events
80
+ end
87
81
 
88
- ```rb
89
- # file: otherapp/app/subscribers/user_events.rb
90
- Chasqui.subscribe 'com.example.myapp', queue: 'unique_queue_name_for_app' do
82
+ You can have as many subscribers as you like, but __each subscriber must have
83
+ its own unique queue name__.
91
84
 
92
- on 'user.sign-up' do |user_id|
93
- user = User.find user_id
94
- UserMailer.signup(user).deliver
95
- end
85
+ Here is how you can run the subscriber as a sidekiq worker:
96
86
 
97
- on 'user.cancel' do |user_id, reason|
98
- user = User.find user_id
99
- AdminMailer.user_cancelled(user, reason).deliver
100
- user.archive!
101
- end
87
+ sidekiq -r subscriber.rb
102
88
 
103
- end
104
- ```
89
+ To run the resque worker, you first need to create a Rakefile.
105
90
 
106
- ## Configure Chasqui
91
+ # Rakefile
92
+ require 'resque'
93
+ require 'resque/tasks'
107
94
 
108
- ```rb
109
- Chasqui.configure do |config|
110
- config.channel = 'com.example.transcoder'
111
- config.redis = ENV.fetch('REDIS_URL')
112
- config.workers = :sidekiq # or :resque
113
- ...
114
- end
115
- ```
95
+ task 'resque:setup' => ['chasqui:subscriber']
116
96
 
117
- ## Running the broker
97
+ namespace :chasqui do
98
+ task :subscriber do
99
+ require './subscriber.rb'
100
+ end
101
+ end
118
102
 
119
- Installing and running Chasqui on Ubuntu using the system ruby.
103
+ Then you can run the resque worker to start processing events.
120
104
 
121
- ```sh
122
- # install required dependencies
123
- $ sudo apt-get install ruby redis-server
105
+ rake resque:work
124
106
 
125
- # install chasqui
126
- $ sudo gem install chasqui --no-ri --no-rdoc
107
+ ## Why Chasqui?
127
108
 
128
- # run chasqui
129
- $ chasqui
130
- I, [2015-09-23T00:58:16.630857 #2420] INFO -- chasqui: broker started with pid 2420
131
- I, [2015-09-23T00:58:16.631147 #2420] INFO -- chasqui: configured to fetch events from inbox on #<Redis client v3.2.1 for redis://127.0.0.1:6379/0>
132
- ```
109
+ * Reduces coupling between applications
110
+ * Integrates with the popular sidekiq and resque background worker libraries
111
+ * Queues events for registered subscribers even if a subscriber is unavailable
133
112
 
134
- There is also a sample Upstart init script in [examples/upstart.conf](examples/upstart.conf).
113
+ ## Limitations
135
114
 
136
- If you prefer a different distro or init system, please consider opening a pull-request. Your efforts will be greatly admired and appreciated!
115
+ In order for chasqui to work properly, the publisher, broker, and all
116
+ subscribers must connect to the same Redis database.
137
117
 
138
118
  ## Contributing
139
119
 
data/lib/chasqui.rb CHANGED
@@ -32,8 +32,9 @@ module Chasqui
32
32
  redis.lpush inbox_queue, build_payload(event, *args).to_json
33
33
  end
34
34
 
35
- def subscribe(channel, options={}, &block)
35
+ def subscribe(options={}, &block)
36
36
  queue = options.fetch :queue
37
+ channel = options.fetch :channel, config.channel
37
38
 
38
39
  create_subscription(queue, channel).tap do |subscription|
39
40
  subscription.subscriber.evaluate(&block) if block_given?
@@ -18,7 +18,6 @@ module Chasqui
18
18
  end
19
19
 
20
20
  def worker
21
- # TODO How can we store this in an instance variable without breaking things?
22
21
  case worker_backend
23
22
  when :resque
24
23
  Chasqui::ResqueWorker.create subscriber
@@ -33,7 +32,15 @@ module Chasqui
33
32
  private
34
33
 
35
34
  def worker_backend
36
- Chasqui.config.worker_backend
35
+ Chasqui.config.worker_backend || find_first_available_worker_backend
36
+ end
37
+
38
+ def find_first_available_worker_backend
39
+ if Object.const_defined? :Sidekiq
40
+ :sidekiq
41
+ elsif Object.const_defined? :Resque
42
+ :resque
43
+ end
37
44
  end
38
45
 
39
46
  SUPPORTED_WORKER_BACKENDS = [:resque, :sidekiq].freeze
@@ -1,3 +1,3 @@
1
1
  module Chasqui
2
- VERSION = "0.9.2"
2
+ VERSION = "0.9.3"
3
3
  end
@@ -1,7 +1,6 @@
1
1
  require 'chasqui'
2
- Chasqui.config.worker_backend = :resque
3
-
4
2
  require 'resque'
3
+
5
4
  Resque.redis = ENV['REDIS_URL'] if ENV['REDIS_URL']
6
5
  Resque.redis.namespace = :resque
7
6
 
@@ -1,8 +1,6 @@
1
1
  require 'chasqui'
2
2
  require 'sidekiq'
3
3
 
4
- Chasqui.config.worker_backend = :sidekiq
5
-
6
4
  Sidekiq.configure_server do |config|
7
5
  config.redis = { url: ENV['REDIS_URL'], namespace: ENV['REDIS_NAMESPACE'] }
8
6
  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 'integration', queue: 'app1' do
7
+ Chasqui.subscribe channel: 'integration', queue: 'app1' do
8
8
  on('user.signup') { |*args| log_event self, args }
9
9
  end
10
10
 
11
- Chasqui.subscribe 'integration', queue: 'app2' do
11
+ Chasqui.subscribe channel: '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
@@ -13,9 +13,9 @@ describe Chasqui::MultiBroker do
13
13
  describe '#forward_event' do
14
14
  before do
15
15
  Chasqui.config.channel = 'app1'
16
- Chasqui.subscribe 'app1', queue: 'queue1'
17
- Chasqui.subscribe 'app2', queue: 'queue2'
18
- Chasqui.subscribe 'app1', queue: 'queue3'
16
+ Chasqui.subscribe channel: 'app1', queue: 'queue1'
17
+ Chasqui.subscribe channel: 'app2', queue: 'queue2'
18
+ Chasqui.subscribe channel: 'app1', queue: 'queue3'
19
19
  end
20
20
 
21
21
  it 'places the event on all subscriber queues' do
@@ -9,6 +9,9 @@ describe Chasqui::Subscription do
9
9
  describe '#worker' do
10
10
  it 'raises when no worker backend configured' do
11
11
  Chasqui.config.worker_backend = nil
12
+ allow_any_instance_of(Chasqui::Subscription).to receive(
13
+ :worker_backend).and_return(nil)
14
+
12
15
  expect(-> {
13
16
  new_subscription.worker
14
17
  }).to raise_error(Chasqui::ConfigurationError)
@@ -134,16 +134,27 @@ describe Chasqui do
134
134
  describe '.subscribe' do
135
135
  before do
136
136
  reset_chasqui
137
+ Resque.redis.namespace = :resque
137
138
  Chasqui.config.worker_backend = :resque
138
139
  end
139
140
 
141
+ context 'with defaults' do
142
+ it 'subscribes to events on the default channel' do
143
+ sub = Chasqui.subscribe queue: 'my-queue'
144
+
145
+ channel = Chasqui.config.channel
146
+ queues = Chasqui.redis.smembers Chasqui.subscription_key(channel)
147
+ expect(queues).to eq(['resque/resque:queue:my-queue'])
148
+ end
149
+ end
150
+
140
151
  context 'resque worker subscriptions' do
141
152
  before { Resque.redis.namespace = 'blah' }
142
153
 
143
154
  it 'creates subscriptions using the appropriate redis namespace' do
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'
155
+ sub1 = Chasqui.subscribe channel: 'com.example.admin', queue: 'app1-queue'
156
+ sub2 = Chasqui.subscribe channel: 'com.example.admin', queue: 'app2-queue'
157
+ sub3 = Chasqui.subscribe channel: 'com.example.video', queue: 'app1-queue'
147
158
 
148
159
  queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.admin")
149
160
  expect(queues.sort).to eq(['resque/blah:queue:app1-queue', 'resque/blah:queue:app2-queue'])
@@ -164,12 +175,12 @@ describe Chasqui do
164
175
  end
165
176
 
166
177
  it 'creates subscriptions using the appropriate redis namespace' do
167
- Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
178
+ Chasqui.subscribe channel: 'com.example.admin', queue: 'app1-queue'
168
179
  queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.admin")
169
180
  expect(queues.sort).to eq(['sidekiq/queue:app1-queue'])
170
181
 
171
182
  Sidekiq.redis = { url: redis.client.options[:url], namespace: 'foobar' }
172
- Chasqui.subscribe 'com.example.video', queue: 'app2-queue'
183
+ Chasqui.subscribe channel: 'com.example.video', queue: 'app2-queue'
173
184
  queues = Chasqui.redis.smembers Chasqui.subscription_key("com.example.video")
174
185
  expect(queues.sort).to eq(['sidekiq/foobar:queue:app2-queue'])
175
186
  end
@@ -177,13 +188,13 @@ describe Chasqui do
177
188
  end
178
189
 
179
190
  it 'returns a subscription' do
180
- subscription = Chasqui.subscribe 'com.example.admin', queue: 'app1-queue'
191
+ subscription = Chasqui.subscribe channel: 'com.example.admin', queue: 'app1-queue'
181
192
  expect(subscription.subscriber).to be_kind_of(Chasqui::Subscriber)
182
193
  end
183
194
 
184
195
  it 'yields a subscriber configuration context' do
185
196
  $context = nil
186
- Chasqui.subscribe 'bar', queue: 'foo' do
197
+ Chasqui.subscribe channel: 'bar', queue: 'foo' do
187
198
  $context = self
188
199
  end
189
200
  expect($context).to be_kind_of(Chasqui::Subscriber)
@@ -195,9 +206,9 @@ describe Chasqui do
195
206
  reset_chasqui
196
207
  Chasqui.config.worker_backend = :resque
197
208
  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'
209
+ Chasqui.subscribe channel: 'com.example.admin', queue: 'app1-queue'
210
+ Chasqui.subscribe channel: 'com.example.admin', queue: 'app2-queue'
211
+ Chasqui.subscribe channel: 'com.example.video', queue: 'app1-queue'
201
212
  end
202
213
 
203
214
  it 'removes the subscription' do
@@ -1,8 +1,8 @@
1
1
  module ChasquiSpecHelpers
2
2
 
3
3
  def reset_chasqui
4
- reset_config
5
4
  flush_redis
5
+ reset_config
6
6
  end
7
7
 
8
8
  def reset_config
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.9.2
4
+ version: 0.9.3
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-11-10 00:00:00.000000000 Z
11
+ date: 2015-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -156,7 +156,6 @@ files:
156
156
  - bin/console
157
157
  - chasqui.gemspec
158
158
  - code-of-conduct.md
159
- - examples/full.rb
160
159
  - examples/upstart.conf
161
160
  - lib/chasqui.rb
162
161
  - lib/chasqui/broker.rb
data/examples/full.rb DELETED
@@ -1,56 +0,0 @@
1
- # file: admin/config/initializers/chasqui.rb
2
- Chasqui.configure do |config|
3
- config.channel = 'com.example.admin'
4
- config.redis = ENV.fetch('REDIS_URL')
5
- end
6
-
7
- # file: admin/app/controllers/video_controller.rb
8
- class VideosController < ApplicationController
9
-
10
- def upload
11
- video = Video.find params[:id]
12
-
13
- if video.upload params[:file]
14
- Chasqui.publish 'video.upload', video.id
15
- redirect_to upload_complete_url,
16
- else
17
- redirect_to video_url, alert: "Upload failed."
18
- end
19
- end
20
-
21
- end
22
-
23
- # file: transcoder/config/initializers/chasqui.rb
24
- Chasqui.configure do |config|
25
- config.publish 'com.example.transcoder'
26
- config.redis ENV.fetch('REDIS_URL')
27
- config.workers :sidekiq # or :resque
28
- end
29
-
30
- # file: transcoder/app/subscribers/video_subscriber.rb
31
- Chasqui.subscribe 'com.example.admin', queue: 'transcoder.video' do
32
- on 'video.upload' do |video_id|
33
- begin
34
- Transcorder.transcode video_url(video_id)
35
- Chasqui.publish 'video.complete', video_id
36
- rescue => ex
37
- Chasqui.publish 'video.error', video_id, ex.message
38
- raise
39
- end
40
- end
41
- end
42
-
43
- # file: admin/app/subscribers/video_subscriber.rb
44
- Chasqui.subscribe 'com.example.transcoder', queue: 'admin.events' do
45
-
46
- on 'transcoder.video.complete' do |video_id|
47
- video = Video.find video_id
48
- VideoMailer.transcode_complete(video).deliver
49
- end
50
-
51
- on 'transcoder.video.error' do |video_id, error|
52
- video = Video.find video_id
53
- VideoMailer.transcode_error(video, error).deliver
54
- end
55
-
56
- end