songkick_queue 0.5.0 → 0.6.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/CHANGELOG.md +30 -0
- data/README.md +21 -2
- data/examples/consumer.rb +5 -0
- data/examples/producer.rb +5 -0
- data/lib/songkick_queue.rb +2 -0
- data/lib/songkick_queue/producer.rb +12 -3
- data/lib/songkick_queue/version.rb +1 -1
- data/lib/songkick_queue/worker.rb +23 -9
- data/songkick_queue.gemspec +2 -1
- data/spec/songkick_queue/worker_spec.rb +6 -31
- metadata +35 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c907eaed6febf237e49b8ff56171ecdd09976fe1
|
4
|
+
data.tar.gz: ac2c3f1207df01dd24623fef5de6492c1b8016ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c1f1c1cd6b38341badd1b4a0065278730ed6caac7193c4d1c35a374076cd0151bad596eb0b00b7abbba312ae67fe5ff6619978b54e176cdee0e372ce8f02702
|
7
|
+
data.tar.gz: 3d21e628d13199e1467e8bb483432ec6abfe31fbfde4cda5858693450ec1faea565fe1848eb83ddfa2376c4f843739cb8ca0842cba285a9254629b65d01671b5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,35 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.6.0
|
4
|
+
### Added
|
5
|
+
- Instrumentation (for tracking metrics using statsd or other tools)
|
6
|
+
- Message ID and produced at timestamp to consumer logs
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
- Bunny gem dependency to `~> 2.2`
|
10
|
+
- Reset reconnect attempts back to zero if message is successfully published
|
11
|
+
|
12
|
+
## 0.5.0
|
13
|
+
### Added
|
14
|
+
- Configuration options: `max_reconnect_attempts` and `network_recovery_interval`
|
15
|
+
- Reconnect handling on closed connections in producer
|
16
|
+
|
17
|
+
## 0.4.0
|
18
|
+
### Added
|
19
|
+
- Configuration option: `heartbeat_interval`
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
- Configuration values: replaced single AMQP string with individual config options (eg. host, port etc...)
|
23
|
+
|
24
|
+
### Removed
|
25
|
+
- Configuration option: `queue_namespace` as RabbitMQ native VHOST can be used instead
|
26
|
+
|
27
|
+
## 0.3.0
|
28
|
+
### Added
|
29
|
+
- Message ID to payload
|
30
|
+
- Produced at timestamp to payload
|
31
|
+
- Improved documentation
|
32
|
+
|
3
33
|
## 0.2.0
|
4
34
|
### Added
|
5
35
|
- Configuration option: `queue_namespace` to namespace queue names when
|
data/README.md
CHANGED
@@ -71,8 +71,6 @@ class TweetConsumer
|
|
71
71
|
TwitterClient.send_tweet(message[:text], message[:user_id])
|
72
72
|
rescue TwitterClient::HttpError => e
|
73
73
|
logger.warn(e)
|
74
|
-
rescue StandardError => e
|
75
|
-
logger.error(e)
|
76
74
|
end
|
77
75
|
end
|
78
76
|
```
|
@@ -125,6 +123,27 @@ consumer.
|
|
125
123
|
SongkickQueue.publish('notifications-service.tweets', { text: 'Hello world', user_id: 57237722 })
|
126
124
|
```
|
127
125
|
|
126
|
+
## Instrumentation
|
127
|
+
|
128
|
+
Hooks are provided to instrument producing and consuming of messages using [ActiveSupport's Notifications](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) API.
|
129
|
+
|
130
|
+
You can subscribe to the following events:
|
131
|
+
|
132
|
+
```
|
133
|
+
consume_message.songkick_queue
|
134
|
+
produce_message.songkick_queue
|
135
|
+
```
|
136
|
+
|
137
|
+
For both events, the payload includes the message id, produced at timestamp and queue name. The `consume_message` event also includes the consumer class.
|
138
|
+
|
139
|
+
For example:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
ActiveSupport::Notifications.subscribe('consume_message.songkick_queue') do |name, start, finish, id, payload|
|
143
|
+
# Log info to statsd or something similar
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
128
147
|
## Tests
|
129
148
|
|
130
149
|
See the current build status on Travis CI: https://travis-ci.org/songkick/queue
|
data/examples/consumer.rb
CHANGED
@@ -10,6 +10,11 @@ SongkickQueue.configure do |config|
|
|
10
10
|
config.logger = Logger.new(STDOUT)
|
11
11
|
end
|
12
12
|
|
13
|
+
ActiveSupport::Notifications.subscribe('consume_message.songkick_queue') do |*args|
|
14
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
15
|
+
SongkickQueue.configuration.logger.info "name: #{event.name}, duration: #{event.duration}, payload: #{event.payload}"
|
16
|
+
end
|
17
|
+
|
13
18
|
class TweetConsumer
|
14
19
|
include SongkickQueue::Consumer
|
15
20
|
|
data/examples/producer.rb
CHANGED
@@ -10,6 +10,11 @@ SongkickQueue.configure do |config|
|
|
10
10
|
config.logger = Logger.new(STDOUT)
|
11
11
|
end
|
12
12
|
|
13
|
+
ActiveSupport::Notifications.subscribe('produce_message.songkick_queue') do |*args|
|
14
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
15
|
+
SongkickQueue.configuration.logger.info "name: #{event.name}, duration: #{event.duration}, payload: #{event.payload}"
|
16
|
+
end
|
17
|
+
|
13
18
|
3.times do
|
14
19
|
SongkickQueue.publish('notifications-service.tweets', { text: 'Hello world', user_id: 57237722 })
|
15
20
|
end
|
data/lib/songkick_queue.rb
CHANGED
@@ -30,9 +30,18 @@ module SongkickQueue
|
|
30
30
|
|
31
31
|
message = JSON.generate(message)
|
32
32
|
|
33
|
-
exchange = client
|
34
|
-
|
35
|
-
|
33
|
+
exchange = client.default_exchange
|
34
|
+
|
35
|
+
instrumentation_options = {
|
36
|
+
queue_name: String(queue_name),
|
37
|
+
message_id: message_id,
|
38
|
+
produced_at: produced_at,
|
39
|
+
}
|
40
|
+
ActiveSupport::Notifications.instrument('produce_message.songkick_queue', instrumentation_options) do
|
41
|
+
exchange.publish(message, routing_key: String(queue_name))
|
42
|
+
end
|
43
|
+
|
44
|
+
self.reconnect_attempts = 0
|
36
45
|
|
37
46
|
logger.info "Published message #{message_id} to '#{queue_name}' at #{produced_at}"
|
38
47
|
|
@@ -83,15 +83,24 @@ module SongkickQueue
|
|
83
83
|
def process_message(consumer_class, delivery_info, properties, message)
|
84
84
|
message = JSON.parse(message, symbolize_names: true)
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
payload = message.fetch(:payload
|
86
|
+
message_id = message.fetch(:message_id)
|
87
|
+
produced_at = message.fetch(:produced_at)
|
88
|
+
payload = message.fetch(:payload)
|
89
89
|
|
90
|
-
logger.info "Processing message via #{consumer_class}
|
91
|
-
set_process_name(consumer_class)
|
90
|
+
logger.info "Processing message #{message_id} via #{consumer_class}, produced at #{produced_at}"
|
91
|
+
set_process_name(consumer_class, message_id)
|
92
92
|
|
93
93
|
consumer = consumer_class.new(delivery_info, logger)
|
94
|
-
|
94
|
+
|
95
|
+
instrumentation_options = {
|
96
|
+
consumer_class: consumer_class.to_s,
|
97
|
+
queue_name: consumer_class.queue_name,
|
98
|
+
message_id: message_id,
|
99
|
+
produced_at: produced_at,
|
100
|
+
}
|
101
|
+
ActiveSupport::Notifications.instrument('consume_message.songkick_queue', instrumentation_options) do
|
102
|
+
consumer.process(payload)
|
103
|
+
end
|
95
104
|
rescue Object => exception
|
96
105
|
logger.error(exception)
|
97
106
|
ensure
|
@@ -116,14 +125,19 @@ module SongkickQueue
|
|
116
125
|
# @example idle
|
117
126
|
# set_process_name #=> "songkick_queue[idle]"
|
118
127
|
# @example consumer running, namespace is removed
|
119
|
-
# set_process_name(Foo::TweetConsumer) #=> "songkick_queue[TweetConsumer]"
|
128
|
+
# set_process_name(Foo::TweetConsumer, 'a729bcd8') #=> "songkick_queue[TweetConsumer#a729bcd8]"
|
120
129
|
# @param status [String] of the program
|
121
|
-
|
130
|
+
# @param message_id [String] identifying the message currently being consumed
|
131
|
+
def set_process_name(status = 'idle', message_id = nil)
|
122
132
|
formatted_status = String(status)
|
123
133
|
.split('::')
|
124
134
|
.last
|
125
135
|
|
126
|
-
|
136
|
+
ident = [formatted_status, message_id]
|
137
|
+
.compact
|
138
|
+
.join('#')
|
139
|
+
|
140
|
+
$PROGRAM_NAME = "#{process_name}[#{ident}]"
|
127
141
|
end
|
128
142
|
end
|
129
143
|
end
|
data/songkick_queue.gemspec
CHANGED
@@ -25,5 +25,6 @@ Gem::Specification.new do |spec|
|
|
25
25
|
# Used by yardoc for processing README.md code snippets
|
26
26
|
spec.add_development_dependency "redcarpet"
|
27
27
|
|
28
|
-
spec.add_dependency "bunny", "
|
28
|
+
spec.add_dependency "bunny", "~> 2.2"
|
29
|
+
spec.add_dependency "activesupport", ">= 3.0.0"
|
29
30
|
end
|
@@ -66,36 +66,11 @@ module SongkickQueue
|
|
66
66
|
|
67
67
|
describe "#process_message" do
|
68
68
|
it "should instantiate the consumer and call #process" do
|
69
|
-
::
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
channel = double(:channel, ack: :null)
|
76
|
-
allow(worker).to receive(:channel) { channel }
|
77
|
-
|
78
|
-
delivery_info = double(:delivery_info, delivery_tag: 'tag')
|
79
|
-
|
80
|
-
consumer = double(FooConsumer, process: :null)
|
81
|
-
|
82
|
-
expect(FooConsumer).to receive(:new)
|
83
|
-
.with(delivery_info, logger) { consumer }
|
84
|
-
|
85
|
-
expect(consumer).to receive(:process)
|
86
|
-
.with({ example: 'message', value: true})
|
87
|
-
|
88
|
-
worker.send(:process_message, FooConsumer, delivery_info,
|
89
|
-
:properties, '{"example":"message","value":true}')
|
90
|
-
|
91
|
-
expect(logger).to have_received(:info)
|
92
|
-
.with('Processing message via FooConsumer...')
|
93
|
-
|
94
|
-
expect(channel).to have_received(:ack).with('tag', false)
|
95
|
-
end
|
96
|
-
|
97
|
-
it "should handle new message format with nested payload" do
|
98
|
-
::BarConsumer = Class.new
|
69
|
+
::BarConsumer = Struct.new(:delivery_info, :logger) do
|
70
|
+
def self.queue_name
|
71
|
+
"bar-queue"
|
72
|
+
end
|
73
|
+
end
|
99
74
|
worker = Worker.new(:process_name, BarConsumer)
|
100
75
|
|
101
76
|
logger = double(:logger, info: :null)
|
@@ -119,7 +94,7 @@ module SongkickQueue
|
|
119
94
|
'"payload":{"example":"message","value":true}}')
|
120
95
|
|
121
96
|
expect(logger).to have_received(:info)
|
122
|
-
.with('Processing message via BarConsumer
|
97
|
+
.with('Processing message 92c583bdc248 via BarConsumer, produced at 2015-03-30T15:41:55Z')
|
123
98
|
|
124
99
|
expect(channel).to have_received(:ack).with('tag', false)
|
125
100
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: songkick_queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Lucraft
|
@@ -9,78 +9,92 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-10-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - ~>
|
18
|
+
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '10.0'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - ~>
|
25
|
+
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '10.0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rspec
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - ~>
|
32
|
+
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '3.2'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - ~>
|
39
|
+
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '3.2'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: yard
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- -
|
46
|
+
- - ">="
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: '0'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- -
|
53
|
+
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: redcarpet
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- -
|
60
|
+
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '0'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: bunny
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- -
|
74
|
+
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
76
|
+
version: '2.2'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version:
|
83
|
+
version: '2.2'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: activesupport
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 3.0.0
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 3.0.0
|
84
98
|
description: A gem for processing tasks asynchronously, powered by RabbitMQ.
|
85
99
|
email:
|
86
100
|
- dan.lucraft@songkick.com
|
@@ -90,10 +104,10 @@ executables:
|
|
90
104
|
extensions: []
|
91
105
|
extra_rdoc_files: []
|
92
106
|
files:
|
93
|
-
- .gitignore
|
94
|
-
- .rspec
|
95
|
-
- .travis.yml
|
96
|
-
- .yardopts
|
107
|
+
- ".gitignore"
|
108
|
+
- ".rspec"
|
109
|
+
- ".travis.yml"
|
110
|
+
- ".yardopts"
|
97
111
|
- CHANGELOG.md
|
98
112
|
- Gemfile
|
99
113
|
- LICENSE.txt
|
@@ -126,17 +140,17 @@ require_paths:
|
|
126
140
|
- lib
|
127
141
|
required_ruby_version: !ruby/object:Gem::Requirement
|
128
142
|
requirements:
|
129
|
-
- -
|
143
|
+
- - ">="
|
130
144
|
- !ruby/object:Gem::Version
|
131
145
|
version: '0'
|
132
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
147
|
requirements:
|
134
|
-
- -
|
148
|
+
- - ">="
|
135
149
|
- !ruby/object:Gem::Version
|
136
150
|
version: '0'
|
137
151
|
requirements: []
|
138
152
|
rubyforge_project:
|
139
|
-
rubygems_version: 2.4.
|
153
|
+
rubygems_version: 2.4.5
|
140
154
|
signing_key:
|
141
155
|
specification_version: 4
|
142
156
|
summary: A gem for processing tasks asynchronously, powered by RabbitMQ.
|