announce 0.2.0 → 0.3.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 +4 -4
- data/.travis.yml +3 -2
- data/README.md +40 -4
- data/announce.gemspec +2 -1
- data/lib/announce/adapters/base_adapter.rb +20 -13
- data/lib/announce/adapters/inline_adapter.rb +2 -4
- data/lib/announce/adapters/shoryuken_adapter.rb +88 -49
- data/lib/announce/adapters/test_adapter.rb +11 -4
- data/lib/announce/configuration.rb +13 -9
- data/lib/announce/core_ext.rb +7 -7
- data/lib/announce/message.rb +9 -8
- data/lib/announce/publisher.rb +2 -3
- data/lib/announce/railtie.rb +2 -5
- data/lib/announce/subscriber.rb +7 -9
- data/lib/announce/testing.rb +45 -0
- data/lib/announce/version.rb +1 -1
- data/lib/announce.rb +14 -18
- data/lib/tasks/announce.rake +6 -1
- metadata +24 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4197e2523a8f2fde2b5c27b19d7ffff59864c21
|
4
|
+
data.tar.gz: 447f8331968cedbaa1c11d7e412f1a9d49eaf9f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f96f65e1562900251b14ba50068ec9a2926202250deb371c42be86de5f33fc2e792d071a4c7ae0080286c9a44501646f2c096ae164104d3f14c87a2562908ee5
|
7
|
+
data.tar.gz: 3408e11b3d4aa7009532040d42bce7a2f9330771b63412559eea0b04cdd779bd357b572b0004e1d858019b5aa5694729706c30109a1230f9e53a251a2d015336
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -32,7 +32,7 @@ end
|
|
32
32
|
```
|
33
33
|
|
34
34
|
When building a Ruby app or service to receive messages, subscribe a job class to announcements like this:
|
35
|
-
```
|
35
|
+
```ruby
|
36
36
|
require 'announce'
|
37
37
|
|
38
38
|
class SomeCreateJob < ActiveJob::Base
|
@@ -223,7 +223,7 @@ Announce.announce(:story, :publish, id: story.id, {})
|
|
223
223
|
```
|
224
224
|
|
225
225
|
There is also a module you can include to get `publish` and `announce` methods:
|
226
|
-
```
|
226
|
+
```ruby
|
227
227
|
class SomeController
|
228
228
|
include Announce::Publisher
|
229
229
|
|
@@ -247,7 +247,7 @@ Unlike other job libraries which specify the Ruby `Class` for processing as part
|
|
247
247
|
|
248
248
|
To designate that a Ruby class will process a message, you must include the `Announce:Subscriber` module and call `subscribe_to` class method.
|
249
249
|
|
250
|
-
```
|
250
|
+
```ruby
|
251
251
|
require 'announce'
|
252
252
|
|
253
253
|
class SomeCreateJob < ActiveJob::Base
|
@@ -264,7 +264,7 @@ end
|
|
264
264
|
This works because the `Announce::Subscriber` adds the `subscribe_to` class method, but also a default `perform(*args)` instance method that delegates message handling to a job instance method named `"receive_#{subject}_#{action}"`.
|
265
265
|
|
266
266
|
This default `perform` method only passes the message `body` to `receive_subject_action` methods. The `subject`, but `action` and full `message` object are made available as instance properties of the subscriber.
|
267
|
-
```
|
267
|
+
```ruby
|
268
268
|
require 'announce'
|
269
269
|
|
270
270
|
class SomeCreateJob < ActiveJob::Base
|
@@ -302,6 +302,42 @@ For `shoryuken`, `subscribe_to` registers the worker for the appropriate queue,
|
|
302
302
|
|
303
303
|
## Development
|
304
304
|
|
305
|
+
### Testing with Announce
|
306
|
+
|
307
|
+
There is an Announce::Testing module which provides helper methods useful in your tests.
|
308
|
+
To use them add the following lines into your test/spec helper:
|
309
|
+
```ruby
|
310
|
+
# use the testing helper
|
311
|
+
require 'announce/testing'
|
312
|
+
|
313
|
+
# include the methods - could also include in your base test class
|
314
|
+
include Announce::Testing
|
315
|
+
|
316
|
+
# this resets announce to use test settings, and clears messages
|
317
|
+
reset_announce
|
318
|
+
|
319
|
+
```
|
320
|
+
|
321
|
+
Then you can use the following methods in your test class:
|
322
|
+
|
323
|
+
`published_messages` - returns the array of published messages
|
324
|
+
|
325
|
+
`last_message` - returns the last message published to announce
|
326
|
+
|
327
|
+
`clear_messages` - clears all published messages
|
328
|
+
|
329
|
+
`subscriptions` - returns the array of all subscriptions
|
330
|
+
|
331
|
+
`last_subscription` - returns most recently added subscription
|
332
|
+
|
333
|
+
`clear_subscriptions` - clears all subscriptions
|
334
|
+
|
335
|
+
`broker_configured?` - returns whether or not the broker has been configured
|
336
|
+
|
337
|
+
`reset_broker_config` - resets broker
|
338
|
+
|
339
|
+
`reset_announce` - resets announce to use test adapter, prefix, app, and logging to `/dev/null`
|
340
|
+
|
305
341
|
### Developing an Adapter Class
|
306
342
|
|
307
343
|
Adapter classes should be named with the following module structure: `Announce::Adapters::SomeBrokerAdapter`
|
data/announce.gemspec
CHANGED
@@ -19,12 +19,13 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
|
-
spec.add_development_dependency 'shoryuken', '~>
|
22
|
+
spec.add_development_dependency 'shoryuken', '~> 2.0.5'
|
23
23
|
spec.add_development_dependency 'bundler'
|
24
24
|
spec.add_development_dependency 'rake'
|
25
25
|
spec.add_development_dependency 'growl'
|
26
26
|
spec.add_development_dependency 'minitest'
|
27
27
|
spec.add_development_dependency 'guard'
|
28
|
+
spec.add_development_dependency 'listen', '~> 3.2.0'
|
28
29
|
spec.add_development_dependency 'guard-minitest'
|
29
30
|
spec.add_development_dependency 'dotenv'
|
30
31
|
spec.add_development_dependency 'simplecov'
|
@@ -1,33 +1,37 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "announce"
|
2
|
+
require "announce/message"
|
3
3
|
|
4
|
-
# publish, subscribe,
|
5
|
-
#
|
6
|
-
# you
|
4
|
+
# publish, subscribe, & configure_broker are the 3 required methods for adapters
|
5
|
+
# the base adapter also has helpful base classes, but they are not necessary
|
6
|
+
# you can write an adapter from scratch, but these 3 class methods are required.
|
7
7
|
module Announce
|
8
8
|
module Adapters
|
9
9
|
class BaseAdapter
|
10
|
-
|
11
10
|
class << self
|
12
|
-
|
11
|
+
# required
|
13
12
|
def publish(subject, action, body, options = {})
|
14
13
|
topic = adapter_constantize(:topic).new(subject, action, options)
|
15
|
-
msg =
|
14
|
+
msg =
|
15
|
+
Announce::Message.new(subject: subject, action: action, body: body)
|
16
16
|
topic.publish(msg.to_message, options)
|
17
17
|
end
|
18
18
|
|
19
|
+
# required
|
19
20
|
def subscribe(worker_class, subject, actions = [], options = {})
|
20
21
|
subscriber = adapter_constantize(:subscriber).new
|
21
22
|
subscriber.subscribe(worker_class, subject, actions, options)
|
22
23
|
end
|
23
24
|
|
25
|
+
# required
|
24
26
|
def configure_broker(options)
|
25
27
|
broker_manager = adapter_constantize(:broker_manager).new(options)
|
26
28
|
broker_manager.configure
|
27
29
|
end
|
28
30
|
|
29
31
|
def adapter_constantize(name)
|
30
|
-
|
32
|
+
a_klass = Announce.options[:adapter].to_s.camelize
|
33
|
+
klass = name.to_s.camelize
|
34
|
+
"::Announce::Adapters::#{a_klass}Adapter::#{klass}".constantize
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
@@ -41,8 +45,8 @@ module Announce
|
|
41
45
|
attr_accessor :options
|
42
46
|
|
43
47
|
# uses the configuration
|
44
|
-
def initialize(options =
|
45
|
-
@options = options
|
48
|
+
def initialize(options = {})
|
49
|
+
@options = Announce.options.merge(options)
|
46
50
|
end
|
47
51
|
|
48
52
|
# actually configure the broker queues, topics, and subscriptions
|
@@ -62,6 +66,10 @@ module Announce
|
|
62
66
|
raise NotImplementedError.new("You must implement create.")
|
63
67
|
end
|
64
68
|
|
69
|
+
def verify
|
70
|
+
raise NotImplementedError.new("You must implement verify.")
|
71
|
+
end
|
72
|
+
|
65
73
|
def self.name_for(subject, action)
|
66
74
|
[prefix, namespace, subject, action].join(delimiter)
|
67
75
|
end
|
@@ -93,8 +101,7 @@ module Announce
|
|
93
101
|
end
|
94
102
|
end
|
95
103
|
|
96
|
-
class Topic < Destination
|
97
|
-
end
|
104
|
+
class Topic < Destination; end
|
98
105
|
|
99
106
|
class Queue < Destination
|
100
107
|
def self.name_for(subject, action)
|
@@ -1,9 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require "announce/adapters/base_adapter"
|
2
2
|
|
3
3
|
module Announce
|
4
4
|
module Adapters
|
5
5
|
class InlineAdapter < BaseAdapter
|
6
|
-
|
7
6
|
def self.subscriptions
|
8
7
|
@@subscriptions ||= {}
|
9
8
|
end
|
@@ -34,8 +33,7 @@ module Announce
|
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
class Queue < BaseAdapter::Queue
|
38
|
-
end
|
36
|
+
class Queue < BaseAdapter::Queue; end
|
39
37
|
end
|
40
38
|
end
|
41
39
|
end
|
@@ -1,27 +1,24 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "shoryuken"
|
2
|
+
require "announce/adapters/base_adapter"
|
3
3
|
|
4
4
|
module Announce
|
5
5
|
module Adapters
|
6
6
|
class ShoryukenAdapter < BaseAdapter
|
7
|
-
|
8
7
|
class AnnounceWorker #:nodoc:
|
9
8
|
include Shoryuken::Worker
|
10
9
|
|
11
10
|
shoryuken_options body_parser: :json, auto_delete: true
|
12
11
|
|
13
12
|
# overriden in register_class
|
14
|
-
def job_class
|
15
|
-
end
|
13
|
+
def job_class; end
|
16
14
|
|
17
15
|
def perform(sqs_msg, hash)
|
18
16
|
job = job_class.new(hash)
|
19
|
-
Base.execute(job.serialize)
|
17
|
+
ActiveJob::Base.execute(job.serialize)
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
23
21
|
class Subscriber < BaseAdapter::Subscriber
|
24
|
-
|
25
22
|
def subscribe(worker_class, subject, actions, options)
|
26
23
|
Array(actions).each do |action|
|
27
24
|
queue_name = Queue.name_for(subject, action)
|
@@ -42,22 +39,31 @@ module Announce
|
|
42
39
|
|
43
40
|
def active_job?
|
44
41
|
defined?(::ActiveJob) &&
|
45
|
-
|
46
|
-
|
42
|
+
defined?(ActiveJob::QueueAdapters::ShoryukenAdapter) &&
|
43
|
+
ActiveJob::Base.queue_adapter ==
|
44
|
+
ActiveJob::QueueAdapters::ShoryukenAdapter
|
47
45
|
end
|
48
46
|
end
|
49
47
|
|
50
48
|
class BrokerManager < BaseAdapter::BrokerManager
|
51
|
-
|
52
49
|
# actually configure the broker queues, topics, and subscriptions
|
53
50
|
def configure
|
51
|
+
if options[:verify_only]
|
52
|
+
Announce.logger.warn(
|
53
|
+
"Running Announce BrokerManager configure in verify_only mode."
|
54
|
+
)
|
55
|
+
Announce.logger.warn(
|
56
|
+
"Resources will be logged, not created; please verify they exist."
|
57
|
+
)
|
58
|
+
end
|
54
59
|
configure_publishing && configure_subscribing
|
55
60
|
end
|
56
61
|
|
57
62
|
def configure_publishing
|
58
63
|
(options[:publish] || {}).each do |subject, actions|
|
59
64
|
Array(actions).each do |action|
|
60
|
-
ShoryukenAdapter::Topic.new(subject, action, options)
|
65
|
+
topic = ShoryukenAdapter::Topic.new(subject, action, options)
|
66
|
+
options[:verify_only] ? topic.verify : topic.create
|
61
67
|
end
|
62
68
|
end
|
63
69
|
true
|
@@ -68,9 +74,15 @@ module Announce
|
|
68
74
|
Array(actions).each do |action|
|
69
75
|
topic = ShoryukenAdapter::Topic.new(subject, action, options)
|
70
76
|
queue = ShoryukenAdapter::Queue.new(subject, action, options)
|
71
|
-
|
72
|
-
|
73
|
-
|
77
|
+
if options[:verify_only]
|
78
|
+
topic.verify
|
79
|
+
queue.verify
|
80
|
+
topic.verify_subscription(queue)
|
81
|
+
else
|
82
|
+
topic.create
|
83
|
+
queue.create
|
84
|
+
topic.subscribe(queue)
|
85
|
+
end
|
74
86
|
end
|
75
87
|
end
|
76
88
|
true
|
@@ -78,7 +90,6 @@ module Announce
|
|
78
90
|
end
|
79
91
|
|
80
92
|
class Topic < BaseAdapter::Topic
|
81
|
-
|
82
93
|
def publish(message, options = {})
|
83
94
|
Shoryuken::Client.topics(name).send_message(message, options)
|
84
95
|
end
|
@@ -87,17 +98,28 @@ module Announce
|
|
87
98
|
sns.create_topic(name: name)[:topic_arn]
|
88
99
|
end
|
89
100
|
|
101
|
+
def verify
|
102
|
+
Announce.logger.warn("Verify SNS Topic: #{arn}")
|
103
|
+
end
|
104
|
+
|
105
|
+
def verify_subscription(queue)
|
106
|
+
Announce.logger.warn(
|
107
|
+
"Verify Subscription:\n"\
|
108
|
+
" from SNS Topic: #{arn}\n"\
|
109
|
+
" to SQS Queue: #{queue.arn}"
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
90
113
|
def subscribe(queue)
|
91
|
-
subscription_arn =
|
92
|
-
topic_arn: arn,
|
93
|
-
|
94
|
-
|
95
|
-
)[:subscription_arn]
|
114
|
+
subscription_arn =
|
115
|
+
sns.subscribe(topic_arn: arn, protocol: "sqs", endpoint: queue.arn)[
|
116
|
+
:subscription_arn
|
117
|
+
]
|
96
118
|
|
97
119
|
sns.set_subscription_attributes(
|
98
120
|
subscription_arn: subscription_arn,
|
99
|
-
attribute_name:
|
100
|
-
attribute_value:
|
121
|
+
attribute_name: "RawMessageDelivery",
|
122
|
+
attribute_value: "true"
|
101
123
|
)
|
102
124
|
subscription_arn
|
103
125
|
end
|
@@ -114,14 +136,25 @@ module Announce
|
|
114
136
|
end
|
115
137
|
|
116
138
|
class Queue < BaseAdapter::Queue
|
139
|
+
DLQ_SUFFIX = "failures".freeze
|
117
140
|
|
118
141
|
def create
|
119
|
-
create_attributes = default_options.merge((options[:queues] || {}).stringify_keys)
|
120
|
-
|
121
142
|
dlq_arn = create_dlq
|
122
|
-
create_attributes['RedrivePolicy'] = %Q{{"maxReceiveCount":"10", "deadLetterTargetArn":"#{dlq_arn}"}"}
|
123
143
|
|
124
|
-
|
144
|
+
create_attributes =
|
145
|
+
default_options.merge((options[:queues] || {}).stringify_keys)
|
146
|
+
create_attributes["RedrivePolicy"] =
|
147
|
+
'{"maxReceiveCount":"10", "deadLetterTargetArn":"' + dlq_arn + '"}'
|
148
|
+
|
149
|
+
sqs.create_queue(queue_name: name, attributes: create_attributes)[
|
150
|
+
:queue_url
|
151
|
+
]
|
152
|
+
end
|
153
|
+
|
154
|
+
def verify
|
155
|
+
Announce.logger.warn(
|
156
|
+
"Verify SQS Queue: #{arn}\n\t with DLQ: #{dlq_arn}"
|
157
|
+
)
|
125
158
|
end
|
126
159
|
|
127
160
|
def arn
|
@@ -131,34 +164,40 @@ module Announce
|
|
131
164
|
end
|
132
165
|
|
133
166
|
def create_dlq
|
134
|
-
dlq_name = "#{name}_failures"
|
135
|
-
|
136
167
|
dlq_options = {
|
137
|
-
|
138
|
-
|
168
|
+
"MaximumMessageSize" => (256 * 1024).to_s,
|
169
|
+
"MessageRetentionPeriod" => (2 * 7 * 24 * 60 * 60).to_s
|
170
|
+
# 2 weeks in seconds
|
139
171
|
}
|
140
172
|
|
141
|
-
dlq = sqs.create_queue(
|
142
|
-
queue_name: dlq_name,
|
143
|
-
attributes: dlq_options
|
144
|
-
)
|
173
|
+
dlq = sqs.create_queue(queue_name: dlq_name, attributes: dlq_options)
|
145
174
|
|
146
|
-
attrs =
|
147
|
-
|
148
|
-
|
149
|
-
|
175
|
+
attrs =
|
176
|
+
sqs.get_queue_attributes(
|
177
|
+
queue_url: dlq[:queue_url], attribute_names: %w[QueueArn]
|
178
|
+
)
|
179
|
+
|
180
|
+
attrs.attributes["QueueArn"]
|
181
|
+
end
|
150
182
|
|
151
|
-
|
183
|
+
def dlq_arn
|
184
|
+
[arn, DLQ_SUFFIX].join(self.class.delimiter)
|
185
|
+
end
|
186
|
+
|
187
|
+
def dlq_name
|
188
|
+
[name, DLQ_SUFFIX].join(self.class.delimiter)
|
152
189
|
end
|
153
190
|
|
154
191
|
def default_options
|
155
192
|
{
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
193
|
+
"DelaySeconds" => "0",
|
194
|
+
"MaximumMessageSize" => (256 * 1024).to_s,
|
195
|
+
"VisibilityTimeout" => (60 * 60).to_s,
|
196
|
+
# 1 hour in seconds
|
197
|
+
"ReceiveMessageWaitTimeSeconds" => "0",
|
198
|
+
"MessageRetentionPeriod" => (7 * 24 * 60 * 60).to_s,
|
199
|
+
# 1 week in seconds
|
200
|
+
"Policy" => policy
|
162
201
|
}
|
163
202
|
end
|
164
203
|
|
@@ -172,9 +211,7 @@ module Announce
|
|
172
211
|
{
|
173
212
|
"Sid" => "1",
|
174
213
|
"Effect" => "Allow",
|
175
|
-
"Principal" => {
|
176
|
-
"AWS" => "*"
|
177
|
-
},
|
214
|
+
"Principal" => { "AWS" => "*" },
|
178
215
|
"Action" => "sqs:*",
|
179
216
|
"Resource" => arn,
|
180
217
|
"Condition" => {
|
@@ -195,4 +232,6 @@ module Announce
|
|
195
232
|
end
|
196
233
|
end
|
197
234
|
|
198
|
-
|
235
|
+
unless Shoryuken::Client.account_id
|
236
|
+
Shoryuken::Client.account_id = ENV["AWS_ACCOUNT_ID"]
|
237
|
+
end
|
@@ -1,11 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require "announce/adapters/base_adapter"
|
2
2
|
|
3
3
|
module Announce
|
4
4
|
module Adapters
|
5
5
|
class TestAdapter < BaseAdapter
|
6
|
-
|
7
6
|
class Subscriber < BaseAdapter::Subscriber
|
8
|
-
|
9
7
|
@@subscriptions = []
|
10
8
|
|
11
9
|
def self.subscriptions
|
@@ -35,7 +33,6 @@ module Announce
|
|
35
33
|
end
|
36
34
|
|
37
35
|
class Topic < BaseAdapter::Topic
|
38
|
-
|
39
36
|
@@published_messages = []
|
40
37
|
|
41
38
|
def self.published_messages
|
@@ -50,12 +47,22 @@ module Announce
|
|
50
47
|
def create
|
51
48
|
true
|
52
49
|
end
|
50
|
+
|
51
|
+
def verify
|
52
|
+
Announce.logger.debug("#{self.class.name}: verify #{name}")
|
53
|
+
true
|
54
|
+
end
|
53
55
|
end
|
54
56
|
|
55
57
|
class Queue < BaseAdapter::Queue
|
56
58
|
def create
|
57
59
|
true
|
58
60
|
end
|
61
|
+
|
62
|
+
def verify
|
63
|
+
Announce.logger.debug("#{self.class.name}: verify #{name}")
|
64
|
+
true
|
65
|
+
end
|
59
66
|
end
|
60
67
|
end
|
61
68
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "yaml"
|
2
|
+
require "erb"
|
3
3
|
|
4
4
|
module Announce
|
5
5
|
class Configuration
|
@@ -14,16 +14,18 @@ module Announce
|
|
14
14
|
{}.tap do |defaults|
|
15
15
|
if defined?(ActiveJob)
|
16
16
|
defaults[:queue_name_prefix] = ::ActiveJob::Base.queue_name_prefix
|
17
|
-
defaults[:queue_name_delimiter] =
|
17
|
+
defaults[:queue_name_delimiter] =
|
18
|
+
::ActiveJob::Base.queue_name_delimiter
|
18
19
|
defaults[:adapter] = aj_queue_adapter_name
|
19
20
|
else
|
20
|
-
defaults[:queue_name_prefix] =
|
21
|
-
|
21
|
+
defaults[:queue_name_prefix] =
|
22
|
+
ENV["RAILS_ENV"] || ENV["APP_ENV"] || "development"
|
23
|
+
defaults[:queue_name_delimiter] = "_"
|
22
24
|
defaults[:adapter] = :inline
|
23
25
|
end
|
24
26
|
|
25
|
-
defaults[:app_name] =
|
26
|
-
defaults[:namespace] =
|
27
|
+
defaults[:app_name] = "app"
|
28
|
+
defaults[:namespace] = "announce"
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
@@ -35,7 +37,7 @@ module Announce
|
|
35
37
|
def initialize(options)
|
36
38
|
@options = options
|
37
39
|
base = defined?(Rails) ? Rails.root : Dir.pwd
|
38
|
-
options[:config_file] ||= File.join(base,
|
40
|
+
options[:config_file] ||= File.join(base, "config", "announce.yml")
|
39
41
|
end
|
40
42
|
|
41
43
|
def config_file
|
@@ -45,7 +47,9 @@ module Announce
|
|
45
47
|
def configure
|
46
48
|
defaults = self.class.default_options
|
47
49
|
if File.exist?(config_file)
|
48
|
-
defaults.merge(
|
50
|
+
defaults.merge(
|
51
|
+
YAML.safe_load(ERB.new(IO.read(config_file)).result).symbolize_keys
|
52
|
+
)
|
49
53
|
else
|
50
54
|
Announce.logger.warn "PubSub file #{config_file} does not exist"
|
51
55
|
defaults
|
data/lib/announce/core_ext.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
begin
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
2
|
+
require "active_support/core_ext/hash/keys"
|
3
|
+
require "active_support/core_ext/hash/deep_merge"
|
4
|
+
require "active_support/core_ext/hash/slice"
|
5
5
|
rescue LoadError
|
6
6
|
class Hash
|
7
7
|
def stringify_keys
|
@@ -36,11 +36,11 @@ rescue LoadError
|
|
36
36
|
end
|
37
37
|
|
38
38
|
begin
|
39
|
-
require
|
39
|
+
require "active_support/core_ext/string/inflections"
|
40
40
|
rescue LoadError
|
41
41
|
class String
|
42
42
|
def constantize
|
43
|
-
names = self.split(
|
43
|
+
names = self.split("::")
|
44
44
|
names.shift if names.empty? || names.first.empty?
|
45
45
|
|
46
46
|
constant = Object
|
@@ -54,14 +54,14 @@ rescue LoadError
|
|
54
54
|
string = self
|
55
55
|
string = string.sub(/^[a-z\d]*/) { $&.capitalize }
|
56
56
|
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
57
|
-
string.gsub!(/\//,
|
57
|
+
string.gsub!(/\//, "::")
|
58
58
|
string
|
59
59
|
end
|
60
60
|
|
61
61
|
def underscore
|
62
62
|
camel_cased_word = self
|
63
63
|
return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
|
64
|
-
word = camel_cased_word.to_s.gsub(/::/,
|
64
|
+
word = camel_cased_word.to_s.gsub(/::/, "/")
|
65
65
|
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
66
66
|
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
67
67
|
word.tr!("-", "_")
|
data/lib/announce/message.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
-
require
|
1
|
+
require "securerandom"
|
2
|
+
require "json"
|
2
3
|
|
3
4
|
module Announce
|
4
5
|
class Message
|
5
|
-
|
6
6
|
attr_accessor :options
|
7
7
|
|
8
|
-
def initialize(options={})
|
9
|
-
@options =
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
def initialize(options = {})
|
9
|
+
@options =
|
10
|
+
{
|
11
|
+
"message_id" => ::SecureRandom.uuid,
|
12
|
+
"app" => app,
|
13
|
+
"sent_at" => Time.now.utc
|
14
|
+
}.merge(options).stringify_keys
|
14
15
|
end
|
15
16
|
|
16
17
|
def app
|
data/lib/announce/publisher.rb
CHANGED
data/lib/announce/railtie.rb
CHANGED
data/lib/announce/subscriber.rb
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
module Announce
|
2
2
|
module Subscriber
|
3
|
-
|
4
3
|
def self.included(base)
|
5
|
-
base.class_eval
|
6
|
-
attr_accessor :subject, :action, :message
|
7
|
-
end
|
4
|
+
base.class_eval { attr_accessor :subject, :action, :message }
|
8
5
|
|
9
6
|
base.extend(ClassMethods)
|
10
7
|
end
|
11
8
|
|
12
9
|
module ClassMethods
|
13
|
-
def subscribe_to(subject, actions=[], options = {})
|
10
|
+
def subscribe_to(subject, actions = [], options = {})
|
14
11
|
Announce.subscribe(self, subject, actions, options)
|
15
12
|
end
|
16
13
|
end
|
@@ -25,19 +22,20 @@ module Announce
|
|
25
22
|
@subject = message[:subject]
|
26
23
|
@action = message[:action]
|
27
24
|
|
28
|
-
if [message, subject, action].any?
|
29
|
-
raise "
|
25
|
+
if [message, subject, action].any?(&:nil?)
|
26
|
+
raise "Missing message, subject, or action for '#{event.inspect}'"
|
30
27
|
end
|
31
28
|
|
32
29
|
if respond_to?(delegate_method)
|
33
30
|
public_send(delegate_method, message[:body])
|
34
31
|
else
|
35
|
-
raise "`#{self.class.name}`
|
32
|
+
raise "`#{self.class.name}` subscribed, but doesn't implement " \
|
33
|
+
"`#{delegate_method}` for '#{event.inspect}'"
|
36
34
|
end
|
37
35
|
end
|
38
36
|
|
39
37
|
def delegate_method(message = @message)
|
40
|
-
[
|
38
|
+
["receive", message[:subject], message[:action]].join("_")
|
41
39
|
end
|
42
40
|
end
|
43
41
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'announce/adapters/test_adapter'
|
2
|
+
|
3
|
+
module Announce
|
4
|
+
module Testing
|
5
|
+
def published_messages
|
6
|
+
Announce::Adapters::TestAdapter::Topic.published_messages
|
7
|
+
end
|
8
|
+
|
9
|
+
def last_message
|
10
|
+
published_messages.last
|
11
|
+
end
|
12
|
+
|
13
|
+
def clear_messages
|
14
|
+
published_messages.clear
|
15
|
+
end
|
16
|
+
|
17
|
+
def subscriptions
|
18
|
+
Announce::Adapters::TestAdapter::Subscriber.subscriptions
|
19
|
+
end
|
20
|
+
|
21
|
+
def last_subscription
|
22
|
+
subscriptions.last
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear_subscriptions
|
26
|
+
subscriptions.clear
|
27
|
+
end
|
28
|
+
|
29
|
+
def broker_configured?
|
30
|
+
Announce::Adapters::TestAdapter::BrokerManager.configured?
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset_broker_config
|
34
|
+
Announce::Adapters::TestAdapter::BrokerManager.reset
|
35
|
+
end
|
36
|
+
|
37
|
+
def reset_announce
|
38
|
+
Announce.logger = Logger.new('/dev/null')
|
39
|
+
Announce.options[:adapter] = 'test'
|
40
|
+
Announce.options[:queue_name_prefix] = 'test'
|
41
|
+
Announce.options[:app_name] = 'app'
|
42
|
+
clear_messages
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/announce/version.rb
CHANGED
data/lib/announce.rb
CHANGED
@@ -1,17 +1,16 @@
|
|
1
|
-
require
|
1
|
+
require "logger"
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
3
|
+
require "announce/configuration"
|
4
|
+
require "announce/core_ext"
|
5
|
+
require "announce/message"
|
6
|
+
require "announce/publisher"
|
7
|
+
require "announce/subscriber"
|
8
|
+
require "announce/version"
|
9
|
+
require "announce/railtie" if defined?(Rails)
|
10
10
|
|
11
11
|
module Announce
|
12
12
|
class << self
|
13
|
-
|
14
|
-
def publish(subject, action, message, options={})
|
13
|
+
def publish(subject, action, message, options = {})
|
15
14
|
adapter_class.publish(subject, action, message, options)
|
16
15
|
end
|
17
16
|
|
@@ -21,8 +20,8 @@ module Announce
|
|
21
20
|
adapter_class.subscribe(worker_class, subject, actions, options)
|
22
21
|
end
|
23
22
|
|
24
|
-
def configure_broker
|
25
|
-
adapter_class.configure_broker(options)
|
23
|
+
def configure_broker(opts = {})
|
24
|
+
adapter_class.configure_broker(options.merge(opts))
|
26
25
|
end
|
27
26
|
|
28
27
|
def options
|
@@ -37,15 +36,12 @@ module Announce
|
|
37
36
|
def adapter_class
|
38
37
|
announce_adapter = Announce.options[:adapter]
|
39
38
|
require "announce/adapters/#{announce_adapter.to_s.downcase}_adapter"
|
40
|
-
"::Announce::Adapters::#{announce_adapter.to_s.camelize}Adapter"
|
39
|
+
"::Announce::Adapters::#{announce_adapter.to_s.camelize}Adapter"
|
40
|
+
.constantize
|
41
41
|
end
|
42
42
|
|
43
43
|
def logger
|
44
|
-
@logger ||=
|
45
|
-
Rails.logger
|
46
|
-
else
|
47
|
-
Logger.new(STDOUT)
|
48
|
-
end
|
44
|
+
@logger ||= defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
49
45
|
end
|
50
46
|
|
51
47
|
def logger=(l)
|
data/lib/tasks/announce.rake
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
namespace :announce do
|
2
2
|
|
3
3
|
desc 'Configure the broker destinations'
|
4
|
-
task :
|
4
|
+
task configure_broker: [:environment] do
|
5
5
|
Announce.configure
|
6
6
|
Announce.configure_broker
|
7
7
|
end
|
8
|
+
|
9
|
+
task verify_config: [:environment] do
|
10
|
+
Announce.configure
|
11
|
+
Announce.configure_broker(verify_only: true)
|
12
|
+
end
|
8
13
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: announce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kuklewicz
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: shoryuken
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.0.5
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.0.5
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: listen
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 3.2.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 3.2.0
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: guard-minitest
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -181,13 +195,14 @@ files:
|
|
181
195
|
- lib/announce/publisher.rb
|
182
196
|
- lib/announce/railtie.rb
|
183
197
|
- lib/announce/subscriber.rb
|
198
|
+
- lib/announce/testing.rb
|
184
199
|
- lib/announce/version.rb
|
185
200
|
- lib/tasks/announce.rake
|
186
201
|
homepage: https://github.com/PRX/announce
|
187
202
|
licenses:
|
188
203
|
- MIT
|
189
204
|
metadata: {}
|
190
|
-
post_install_message:
|
205
|
+
post_install_message:
|
191
206
|
rdoc_options: []
|
192
207
|
require_paths:
|
193
208
|
- lib
|
@@ -202,9 +217,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
217
|
- !ruby/object:Gem::Version
|
203
218
|
version: '0'
|
204
219
|
requirements: []
|
205
|
-
rubyforge_project:
|
206
|
-
rubygems_version: 2.
|
207
|
-
signing_key:
|
220
|
+
rubyforge_project:
|
221
|
+
rubygems_version: 2.5.1
|
222
|
+
signing_key:
|
208
223
|
specification_version: 4
|
209
224
|
summary: Announce is for pubsub of messages
|
210
225
|
test_files: []
|