osbourne 0.1.3 → 0.2.2
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/README.md +59 -0
- data/lib/generators/osbourne/worker/templates/worker_template.template +0 -1
- data/lib/osbourne.rb +4 -0
- data/lib/osbourne/config/file_loader.rb +5 -1
- data/lib/osbourne/config/shared_configs.rb +12 -0
- data/lib/osbourne/launcher.rb +0 -1
- data/lib/osbourne/railtie.rb +0 -2
- data/lib/osbourne/runner.rb +1 -0
- data/lib/osbourne/services/queue_provisioner.rb +2 -0
- data/lib/osbourne/test.rb +16 -0
- data/lib/osbourne/test/message.rb +21 -0
- data/lib/osbourne/test/mock_pubsub.rb +17 -0
- data/lib/osbourne/topic.rb +4 -0
- data/lib/osbourne/version.rb +1 -1
- metadata +83 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 699bb698e3dae6272c3038bdc052597e0a6677e8f380bc1f64c12ae1c18c63a0
|
4
|
+
data.tar.gz: ca0bf27de44bff4a2e96755d0c041a73bbb75bc941c7166c44dfdd144630d3e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b464098af275a72c4aa7a2ba600b1bdb709485f4ddaac98462f6513b8c2ae6930c9e8b8bdb478cf58618e39f1d224070957af61fa4633a4032e53ea0e10c3c9e
|
7
|
+
data.tar.gz: 32b5e08de9d525e95408525e0d9c0723383a33d3ac8aa688e323af9c49db1bbb15023e2fde9de099750e10a166770d58e3aba8826392702f61355bfd715bb308
|
data/README.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
[](https://codeclimate.com/github/stevenallen05/osbourne/maintainability) [](https://codeclimate.com/github/stevenallen05/osbourne/test_coverage)
|
2
2
|
|
3
|
+
- [Osbourne](#osbourne)
|
4
|
+
+ [Features](#features)
|
5
|
+
* [Installation](#installation)
|
6
|
+
+ [AWS credentials](#aws-credentials)
|
7
|
+
+ [Production AWS](#production-aws)
|
8
|
+
+ [Mock AWS for local devlopment](#mock-aws-for-local-devlopment)
|
9
|
+
+ [RSpec](#rspec)
|
10
|
+
* [Usage](#usage)
|
11
|
+
+ [Publishing a message](#publishing-a-message)
|
12
|
+
+ [Generating a worker](#generating-a-worker)
|
13
|
+
+ [Running workers](#running-workers)
|
14
|
+
* [License](#license)
|
15
|
+
|
3
16
|
# Osbourne
|
4
17
|
|
5
18
|
A fan-out pubsub message implementation for Rails 5. Named after the world's most famous plumber, Ozzy Osbourne.
|
@@ -11,6 +24,7 @@ A fan-out pubsub message implementation for Rails 5. Named after the world's mos
|
|
11
24
|
* Worker generator via `rails g osbourne:worker worker_name topic`
|
12
25
|
* Auto-provisioning of SQS queues, SNS topics, and subscriptions between them
|
13
26
|
* Built-in support for locking to prevent accidental duplicate message delivery
|
27
|
+
* Test helpers
|
14
28
|
|
15
29
|
Inspired heavily by the excellent Shoryuken & Circuitry gems
|
16
30
|
|
@@ -71,6 +85,51 @@ AWS_REGION=us-east-1
|
|
71
85
|
|
72
86
|
There must be a region set. Use whichever is appropriate for your situation.
|
73
87
|
|
88
|
+
### RSpec
|
89
|
+
|
90
|
+
To turn on test mode, in your spec helper:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
require 'osbourne/test'
|
94
|
+
```
|
95
|
+
|
96
|
+
This will enable test mode for provisioning and publishing. Example:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class TestWorker < Osbourne::WorkerBase
|
100
|
+
worker_config topics: %w[test_topic]
|
101
|
+
|
102
|
+
def process(message)
|
103
|
+
# Do stuff here...
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
RSpec.describe TestWorker do
|
108
|
+
subject(:worker) { described_class.new }
|
109
|
+
|
110
|
+
before do
|
111
|
+
# This will call `#publish` on `TestWorker`
|
112
|
+
Osbourne.publish('test_topic', 'message')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
```
|
117
|
+
|
118
|
+
There is also a test `Message` object you can use and pass directly into your workers. It stubs out the message validation, and creates a mock `message` as if it had been broadcast from SNS.
|
119
|
+
|
120
|
+
Example:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
|
124
|
+
let(:test_worker) { TestWorker.new }
|
125
|
+
let(:message) { Osbourne::Test::Message.new(topic: "test", body: "thing") }
|
126
|
+
|
127
|
+
# Now you can use `test_worker.process(message)` in your specs
|
128
|
+
|
129
|
+
```
|
130
|
+
|
131
|
+
|
132
|
+
|
74
133
|
## Usage
|
75
134
|
|
76
135
|
### Publishing a message
|
@@ -5,7 +5,6 @@ class <%= name.singularize.camelcase %>Worker < Osbourne::WorkerBase
|
|
5
5
|
worker_config topics: %w[<%= topic.join(" ") %>] #, max_batch_size: 10, max_wait: 10
|
6
6
|
|
7
7
|
def process(message)
|
8
|
-
puts message.raw_body # This will always be a string, representing the entirety of the message
|
9
8
|
puts message.parsed_body # If the message came from a SNS broadcast,
|
10
9
|
# as opposed to a direct SQS message, it will come from here
|
11
10
|
puts message.topic # The topic this message was published to.
|
data/lib/osbourne.rb
CHANGED
@@ -25,10 +25,14 @@ module Osbourne
|
|
25
25
|
attr_writer :sns_client, :sqs_client
|
26
26
|
|
27
27
|
def sns_client
|
28
|
+
return if Osbourne.test_mode?
|
29
|
+
|
28
30
|
@sns_client ||= Aws::SNS::Client.new(Osbourne.config.sns_config)
|
29
31
|
end
|
30
32
|
|
31
33
|
def sqs_client
|
34
|
+
return if Osbourne.test_mode?
|
35
|
+
|
32
36
|
@sqs_client ||= Aws::SQS::Client.new(Osbourne.config.sqs_config)
|
33
37
|
end
|
34
38
|
|
@@ -8,7 +8,7 @@ module Osbourne
|
|
8
8
|
module Config
|
9
9
|
module FileLoader
|
10
10
|
def self.load(cfile, environment="development")
|
11
|
-
return
|
11
|
+
return false unless should_run?(cfile)
|
12
12
|
|
13
13
|
base_opts = YAML.safe_load(ERB.new(IO.read(cfile)).result) || {}
|
14
14
|
env_opts = base_opts[environment] || {}
|
@@ -17,6 +17,10 @@ module Osbourne
|
|
17
17
|
Osbourne.config.sqs_config = env_opts["subscriber"].symbolize_keys || {}
|
18
18
|
true
|
19
19
|
end
|
20
|
+
|
21
|
+
def self.should_run?(cfile)
|
22
|
+
File.exist?(cfile) && !Osbourne.test_mode?
|
23
|
+
end
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
@@ -13,6 +13,18 @@ module Osbourne
|
|
13
13
|
config.cache ||= ActiveSupport::Cache::NullStore.new
|
14
14
|
end
|
15
15
|
|
16
|
+
def test_mode?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_mode!
|
21
|
+
@test_mode = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_mode=(test_mode)
|
25
|
+
@test_mode = test_mode
|
26
|
+
end
|
27
|
+
|
16
28
|
def dead_letter
|
17
29
|
config.dead_letter ||= true
|
18
30
|
end
|
data/lib/osbourne/launcher.rb
CHANGED
data/lib/osbourne/railtie.rb
CHANGED
data/lib/osbourne/runner.rb
CHANGED
@@ -4,6 +4,8 @@ module Osbourne
|
|
4
4
|
module Services
|
5
5
|
module QueueProvisioner
|
6
6
|
def provision_worker_queues
|
7
|
+
return if Osbourne.test_mode?
|
8
|
+
|
7
9
|
Osbourne.logger.info "Workers found: #{Osbourne::WorkerBase.descendants.map(&:name).join(', ')}"
|
8
10
|
Osbourne.logger.info "Provisioning queues for all workers"
|
9
11
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "osbourne/test/mock_pubsub"
|
4
|
+
require "osbourne/test/message"
|
5
|
+
|
6
|
+
module Osbourne
|
7
|
+
class << self
|
8
|
+
def test_mode?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def publish(topic, message)
|
13
|
+
Osbourne::Test::MockPubsub.mock_publish(topic, message)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Osbourne
|
4
|
+
module Test
|
5
|
+
class Message
|
6
|
+
attr_reader :topic, :parsed_body
|
7
|
+
def initialize(topic:, body:)
|
8
|
+
@topic = topic
|
9
|
+
@parsed_body = body
|
10
|
+
end
|
11
|
+
|
12
|
+
def id
|
13
|
+
@id ||= SecureRandom.uuid
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "osbourne/test/message"
|
4
|
+
module Osbourne
|
5
|
+
module Test
|
6
|
+
class MockPubsub
|
7
|
+
class << self
|
8
|
+
def mock_publish(topic, message)
|
9
|
+
Osbourne::WorkerBase.descendants.each do |worker|
|
10
|
+
msg = Osbourne::Test::Message.new(topic: topic, body: message)
|
11
|
+
worker.new.process(msg) if worker.config[:topic_names].include? topic
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/osbourne/topic.rb
CHANGED
@@ -14,6 +14,8 @@ module Osbourne
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def publish(message)
|
17
|
+
return if Osbourne.test_mode?
|
18
|
+
|
17
19
|
Osbourne.logger.info "[PUB] TOPIC: `#{name}` MESSAGE: `#{message}`"
|
18
20
|
sns.publish(topic_arn: arn, message: message.is_a?(String) ? message : message.to_json)
|
19
21
|
end
|
@@ -21,6 +23,8 @@ module Osbourne
|
|
21
23
|
private
|
22
24
|
|
23
25
|
def ensure_topic
|
26
|
+
return if Osbourne.test_mode?
|
27
|
+
|
24
28
|
Osbourne.logger.debug "Ensuring topic `#{name}` exists"
|
25
29
|
Osbourne.cache.fetch("osbourne_existing_topic_arn_for_#{name}") do
|
26
30
|
sns.create_topic(name: name).topic_arn
|
data/lib/osbourne/version.rb
CHANGED
metadata
CHANGED
@@ -1,85 +1,109 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: osbourne
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Allen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-10-
|
11
|
+
date: 2018-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-core
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '4'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
|
-
- - "
|
27
|
+
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '3'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '4'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: aws-sdk-sns
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
|
-
- - "
|
37
|
+
- - ">="
|
32
38
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1'
|
39
|
+
version: '1.5'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2'
|
34
43
|
type: :runtime
|
35
44
|
prerelease: false
|
36
45
|
version_requirements: !ruby/object:Gem::Requirement
|
37
46
|
requirements:
|
38
|
-
- - "
|
47
|
+
- - ">="
|
39
48
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1'
|
49
|
+
version: '1.5'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '2'
|
41
53
|
- !ruby/object:Gem::Dependency
|
42
54
|
name: aws-sdk-sqs
|
43
55
|
requirement: !ruby/object:Gem::Requirement
|
44
56
|
requirements:
|
45
|
-
- - "
|
57
|
+
- - ">="
|
46
58
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1'
|
59
|
+
version: '1.6'
|
60
|
+
- - "<"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '2'
|
48
63
|
type: :runtime
|
49
64
|
prerelease: false
|
50
65
|
version_requirements: !ruby/object:Gem::Requirement
|
51
66
|
requirements:
|
52
|
-
- - "
|
67
|
+
- - ">="
|
53
68
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1'
|
69
|
+
version: '1.6'
|
70
|
+
- - "<"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '2'
|
55
73
|
- !ruby/object:Gem::Dependency
|
56
74
|
name: rails
|
57
75
|
requirement: !ruby/object:Gem::Requirement
|
58
76
|
requirements:
|
59
|
-
- - "
|
77
|
+
- - ">="
|
60
78
|
- !ruby/object:Gem::Version
|
61
79
|
version: '5'
|
80
|
+
- - "<"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '6'
|
62
83
|
type: :runtime
|
63
84
|
prerelease: false
|
64
85
|
version_requirements: !ruby/object:Gem::Requirement
|
65
86
|
requirements:
|
66
|
-
- - "
|
87
|
+
- - ">="
|
67
88
|
- !ruby/object:Gem::Version
|
68
89
|
version: '5'
|
90
|
+
- - "<"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '6'
|
69
93
|
- !ruby/object:Gem::Dependency
|
70
94
|
name: thor
|
71
95
|
requirement: !ruby/object:Gem::Requirement
|
72
96
|
requirements:
|
73
|
-
- - "
|
97
|
+
- - ">="
|
74
98
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
99
|
+
version: '0.19'
|
76
100
|
type: :runtime
|
77
101
|
prerelease: false
|
78
102
|
version_requirements: !ruby/object:Gem::Requirement
|
79
103
|
requirements:
|
80
|
-
- - "
|
104
|
+
- - ">="
|
81
105
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
106
|
+
version: '0.19'
|
83
107
|
- !ruby/object:Gem::Dependency
|
84
108
|
name: bundler
|
85
109
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,30 +136,30 @@ dependencies:
|
|
112
136
|
name: guard
|
113
137
|
requirement: !ruby/object:Gem::Requirement
|
114
138
|
requirements:
|
115
|
-
- - "
|
139
|
+
- - ">="
|
116
140
|
- !ruby/object:Gem::Version
|
117
141
|
version: '2'
|
118
142
|
type: :development
|
119
143
|
prerelease: false
|
120
144
|
version_requirements: !ruby/object:Gem::Requirement
|
121
145
|
requirements:
|
122
|
-
- - "
|
146
|
+
- - ">="
|
123
147
|
- !ruby/object:Gem::Version
|
124
148
|
version: '2'
|
125
149
|
- !ruby/object:Gem::Dependency
|
126
150
|
name: guard-bundler
|
127
151
|
requirement: !ruby/object:Gem::Requirement
|
128
152
|
requirements:
|
129
|
-
- - "
|
153
|
+
- - ">="
|
130
154
|
- !ruby/object:Gem::Version
|
131
|
-
version: '2
|
155
|
+
version: '2'
|
132
156
|
type: :development
|
133
157
|
prerelease: false
|
134
158
|
version_requirements: !ruby/object:Gem::Requirement
|
135
159
|
requirements:
|
136
|
-
- - "
|
160
|
+
- - ">="
|
137
161
|
- !ruby/object:Gem::Version
|
138
|
-
version: '2
|
162
|
+
version: '2'
|
139
163
|
- !ruby/object:Gem::Dependency
|
140
164
|
name: guard-rspec
|
141
165
|
requirement: !ruby/object:Gem::Requirement
|
@@ -154,86 +178,98 @@ dependencies:
|
|
154
178
|
name: mock_redis
|
155
179
|
requirement: !ruby/object:Gem::Requirement
|
156
180
|
requirements:
|
157
|
-
- - "
|
181
|
+
- - ">="
|
158
182
|
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
183
|
+
version: '0.19'
|
160
184
|
type: :development
|
161
185
|
prerelease: false
|
162
186
|
version_requirements: !ruby/object:Gem::Requirement
|
163
187
|
requirements:
|
164
|
-
- - "
|
188
|
+
- - ">="
|
165
189
|
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
190
|
+
version: '0.19'
|
167
191
|
- !ruby/object:Gem::Dependency
|
168
192
|
name: pry-byebug
|
169
193
|
requirement: !ruby/object:Gem::Requirement
|
170
194
|
requirements:
|
171
|
-
- - "
|
195
|
+
- - ">="
|
172
196
|
- !ruby/object:Gem::Version
|
173
197
|
version: '3.6'
|
174
198
|
type: :development
|
175
199
|
prerelease: false
|
176
200
|
version_requirements: !ruby/object:Gem::Requirement
|
177
201
|
requirements:
|
178
|
-
- - "
|
202
|
+
- - ">="
|
179
203
|
- !ruby/object:Gem::Version
|
180
204
|
version: '3.6'
|
181
205
|
- !ruby/object:Gem::Dependency
|
182
206
|
name: rake
|
183
207
|
requirement: !ruby/object:Gem::Requirement
|
184
208
|
requirements:
|
185
|
-
- - "
|
209
|
+
- - ">="
|
186
210
|
- !ruby/object:Gem::Version
|
187
|
-
version: '10
|
211
|
+
version: '10'
|
188
212
|
type: :development
|
189
213
|
prerelease: false
|
190
214
|
version_requirements: !ruby/object:Gem::Requirement
|
191
215
|
requirements:
|
192
|
-
- - "
|
216
|
+
- - ">="
|
193
217
|
- !ruby/object:Gem::Version
|
194
|
-
version: '10
|
218
|
+
version: '10'
|
195
219
|
- !ruby/object:Gem::Dependency
|
196
220
|
name: redis
|
197
221
|
requirement: !ruby/object:Gem::Requirement
|
198
222
|
requirements:
|
199
|
-
- - "
|
223
|
+
- - ">="
|
200
224
|
- !ruby/object:Gem::Version
|
201
225
|
version: '4'
|
226
|
+
- - "<"
|
227
|
+
- !ruby/object:Gem::Version
|
228
|
+
version: '5'
|
202
229
|
type: :development
|
203
230
|
prerelease: false
|
204
231
|
version_requirements: !ruby/object:Gem::Requirement
|
205
232
|
requirements:
|
206
|
-
- - "
|
233
|
+
- - ">="
|
207
234
|
- !ruby/object:Gem::Version
|
208
235
|
version: '4'
|
236
|
+
- - "<"
|
237
|
+
- !ruby/object:Gem::Version
|
238
|
+
version: '5'
|
209
239
|
- !ruby/object:Gem::Dependency
|
210
240
|
name: rspec
|
211
241
|
requirement: !ruby/object:Gem::Requirement
|
212
242
|
requirements:
|
213
|
-
- - "
|
243
|
+
- - ">="
|
214
244
|
- !ruby/object:Gem::Version
|
215
|
-
version: '3'
|
245
|
+
version: '3.2'
|
246
|
+
- - "<"
|
247
|
+
- !ruby/object:Gem::Version
|
248
|
+
version: '4'
|
216
249
|
type: :development
|
217
250
|
prerelease: false
|
218
251
|
version_requirements: !ruby/object:Gem::Requirement
|
219
252
|
requirements:
|
220
|
-
- - "
|
253
|
+
- - ">="
|
221
254
|
- !ruby/object:Gem::Version
|
222
|
-
version: '3'
|
255
|
+
version: '3.2'
|
256
|
+
- - "<"
|
257
|
+
- !ruby/object:Gem::Version
|
258
|
+
version: '4'
|
223
259
|
- !ruby/object:Gem::Dependency
|
224
260
|
name: rubocop
|
225
261
|
requirement: !ruby/object:Gem::Requirement
|
226
262
|
requirements:
|
227
|
-
- - "
|
263
|
+
- - ">="
|
228
264
|
- !ruby/object:Gem::Version
|
229
|
-
version: '0'
|
265
|
+
version: '0.50'
|
230
266
|
type: :development
|
231
267
|
prerelease: false
|
232
268
|
version_requirements: !ruby/object:Gem::Requirement
|
233
269
|
requirements:
|
234
|
-
- - "
|
270
|
+
- - ">="
|
235
271
|
- !ruby/object:Gem::Version
|
236
|
-
version: '0'
|
272
|
+
version: '0.50'
|
237
273
|
- !ruby/object:Gem::Dependency
|
238
274
|
name: rubocop-rspec
|
239
275
|
requirement: !ruby/object:Gem::Requirement
|
@@ -316,6 +352,9 @@ files:
|
|
316
352
|
- lib/osbourne/services/sns.rb
|
317
353
|
- lib/osbourne/services/sqs.rb
|
318
354
|
- lib/osbourne/subscription.rb
|
355
|
+
- lib/osbourne/test.rb
|
356
|
+
- lib/osbourne/test/message.rb
|
357
|
+
- lib/osbourne/test/mock_pubsub.rb
|
319
358
|
- lib/osbourne/topic.rb
|
320
359
|
- lib/osbourne/version.rb
|
321
360
|
- lib/osbourne/worker_base.rb
|