pheme 3.4.0 → 4.0.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/.rubocop.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/lib/pheme/message_handler.rb +3 -2
- data/lib/pheme/queue_poller.rb +34 -4
- data/lib/pheme/version.rb +1 -1
- data/pheme.gemspec +1 -1
- data/spec/queue_poller_spec.rb +69 -9
- data/spec/support/example_queue_poller.rb +2 -2
- data/spec/support/example_queue_poller_with_inlined_handler.rb +2 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0711608ea3831e4718cb928b6e3db90bd049c302b5ae864c4e457f3797215add'
|
4
|
+
data.tar.gz: 1387f1048aef3104ff08aad3fb5cdc7d3a542bfbb9b2c71e49f02b78fe67b8c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6ef008cf929f3eb8e6f9d846ee316982e378039f9a40b7900eb52bedd073fbfb80221d6de1dfb72d74b660f7faf75e0bad5d9f20148368d9332446704267dda
|
7
|
+
data.tar.gz: be52cf4fe2479f239568488fd5c498642842bb92646496907598a211700a1ad994fd889fb9d99c8923f411c24c0d258224fddbb3eb88414207ee92aff7bf437e
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## 4.0.0 - 2020-03-18
|
8
|
+
### Breaking Changes
|
9
|
+
- Add the ability for SQS to receive message attributes
|
10
|
+
- `handle` function of `QueuePoller` now takes a third parameter `message_attributes`
|
11
|
+
- blocks or `MessageHandler`s passed to `QueuePoller` can use this `message_attributes`
|
12
|
+
|
7
13
|
## 3.4.0 - 2020-03-17
|
8
14
|
### Added
|
9
15
|
- Add the ability to pass message attributes to SNS
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module Pheme
|
2
2
|
class MessageHandler
|
3
|
-
attr_reader :message, :metadata, :timestamp
|
3
|
+
attr_reader :message, :metadata, :message_attributes, :timestamp
|
4
4
|
|
5
|
-
def initialize(message:, metadata: {})
|
5
|
+
def initialize(message:, metadata: {}, message_attributes: {})
|
6
6
|
@message = message
|
7
7
|
@metadata = metadata
|
8
|
+
@message_attributes = message_attributes
|
8
9
|
end
|
9
10
|
|
10
11
|
def handle
|
data/lib/pheme/queue_poller.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'compression'
|
2
2
|
|
3
3
|
module Pheme
|
4
|
+
# rubocop:disable Metrics/ClassLength
|
4
5
|
class QueuePoller
|
5
6
|
include Compression
|
6
7
|
|
@@ -51,6 +52,7 @@ module Pheme
|
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
55
|
+
# rubocop:disable Metrics/AbcSize
|
54
56
|
def poll
|
55
57
|
time_start = log_polling_start
|
56
58
|
queue_poller.poll(poller_configuration) do |queue_message|
|
@@ -59,7 +61,8 @@ module Pheme
|
|
59
61
|
begin
|
60
62
|
content = parse_body(queue_message)
|
61
63
|
metadata = parse_metadata(queue_message)
|
62
|
-
|
64
|
+
message_attributes = parse_message_attributes(queue_message)
|
65
|
+
with_optional_connection_pool_block { handle(content, metadata, message_attributes) }
|
63
66
|
queue_poller.delete_message(queue_message)
|
64
67
|
log_delete(queue_message)
|
65
68
|
@messages_processed += 1
|
@@ -73,6 +76,7 @@ module Pheme
|
|
73
76
|
end
|
74
77
|
log_polling_end(time_start)
|
75
78
|
end
|
79
|
+
# rubocop:enable Metrics/AbcSize
|
76
80
|
|
77
81
|
# returns queue_message.body as hash,
|
78
82
|
# stores and parses get_content to body[:content]
|
@@ -105,6 +109,15 @@ module Pheme
|
|
105
109
|
{ timestamp: message_body['Timestamp'], topic_arn: message_body['TopicArn'] }
|
106
110
|
end
|
107
111
|
|
112
|
+
def parse_message_attributes(queue_message)
|
113
|
+
message_attributes = {}
|
114
|
+
queue_message.message_attributes&.each do |key, value|
|
115
|
+
message_attributes[key.to_sym] = coerce_message_attribute(value)
|
116
|
+
end
|
117
|
+
|
118
|
+
message_attributes
|
119
|
+
end
|
120
|
+
|
108
121
|
def get_metadata(message_body)
|
109
122
|
message_body.except('Message', 'Records')
|
110
123
|
end
|
@@ -123,11 +136,11 @@ module Pheme
|
|
123
136
|
RecursiveOpenStruct.new({ wrapper: parsed_body }, recurse_over_arrays: true).wrapper
|
124
137
|
end
|
125
138
|
|
126
|
-
def handle(message, metadata)
|
139
|
+
def handle(message, metadata, message_attributes)
|
127
140
|
if @message_handler
|
128
|
-
@message_handler.new(message: message, metadata: metadata).handle
|
141
|
+
@message_handler.new(message: message, metadata: metadata, message_attributes: message_attributes).handle
|
129
142
|
elsif @block_message_handler
|
130
|
-
@block_message_handler.call(message, metadata)
|
143
|
+
@block_message_handler.call(message, metadata, message_attributes)
|
131
144
|
else
|
132
145
|
raise NotImplementedError
|
133
146
|
end
|
@@ -135,6 +148,22 @@ module Pheme
|
|
135
148
|
|
136
149
|
private
|
137
150
|
|
151
|
+
def coerce_message_attribute(value)
|
152
|
+
case value['data_type']
|
153
|
+
when 'String'
|
154
|
+
value['string_value']
|
155
|
+
when 'Number'
|
156
|
+
JSON.parse(value['string_value'])
|
157
|
+
when 'String.Array'
|
158
|
+
JSON.parse(value['string_value'])
|
159
|
+
when 'Binary'
|
160
|
+
value['binary_value']
|
161
|
+
else
|
162
|
+
Pheme.logger.info("Unsupported custom data type")
|
163
|
+
value["binary_value"] || value["string_value"]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
138
167
|
def with_optional_connection_pool_block
|
139
168
|
if connection_pool_block
|
140
169
|
ActiveRecord::Base.connection_pool.with_connection { yield }
|
@@ -192,4 +221,5 @@ module Pheme
|
|
192
221
|
}.to_json)
|
193
222
|
end
|
194
223
|
end
|
224
|
+
# rubocop:enable Metrics/ClassLength
|
195
225
|
end
|
data/lib/pheme/version.rb
CHANGED
data/pheme.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_dependency "smarter_csv", "~> 1"
|
30
30
|
|
31
31
|
s.add_development_dependency 'bundler'
|
32
|
-
s.add_development_dependency 'coveralls'
|
32
|
+
s.add_development_dependency 'coveralls', "~> 0.8"
|
33
33
|
s.add_development_dependency 'git'
|
34
34
|
s.add_development_dependency 'rake'
|
35
35
|
s.add_development_dependency 'rspec'
|
data/spec/queue_poller_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe Pheme::QueuePoller do
|
|
14
14
|
let(:message_id) { SecureRandom.uuid }
|
15
15
|
|
16
16
|
context 'base poller' do
|
17
|
-
subject { described_class.new(queue_url: queue_url).handle(nil, nil) }
|
17
|
+
subject { described_class.new(queue_url: queue_url).handle(nil, nil, nil) }
|
18
18
|
|
19
19
|
it 'does not implement handle' do
|
20
20
|
expect { subject }.to raise_error(NotImplementedError)
|
@@ -90,13 +90,13 @@ describe Pheme::QueuePoller do
|
|
90
90
|
context 'when handling messages' do
|
91
91
|
context 'when doing it the old way, via the handle function' do
|
92
92
|
it 'uses the handle function by default' do
|
93
|
-
expect { described_class.new(queue_url: queue_url).handle(nil, nil) }.to raise_error(NotImplementedError)
|
93
|
+
expect { described_class.new(queue_url: queue_url).handle(nil, nil, nil) }.to raise_error(NotImplementedError)
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
97
|
context 'when given a message_handler as parameter' do
|
98
98
|
it 'uses default when given nil' do
|
99
|
-
expect { described_class.new(queue_url: queue_url, message_handler: nil).handle(nil, nil) }.to raise_error(NotImplementedError)
|
99
|
+
expect { described_class.new(queue_url: queue_url, message_handler: nil).handle(nil, nil, nil) }.to raise_error(NotImplementedError)
|
100
100
|
end
|
101
101
|
|
102
102
|
it 'uses default when given invalid message_handler' do
|
@@ -106,9 +106,11 @@ describe Pheme::QueuePoller do
|
|
106
106
|
it 'uses handler when given one' do
|
107
107
|
mock_handler = double('MessageHandler')
|
108
108
|
allow(mock_handler).to receive(:handle)
|
109
|
-
allow(ExampleMessageHandler).to receive(:new).
|
109
|
+
allow(ExampleMessageHandler).to receive(:new).
|
110
|
+
with(message: 'message', metadata: 'metadata', message_attributes: 'message_attributes').
|
111
|
+
and_return(mock_handler)
|
110
112
|
|
111
|
-
described_class.new(queue_url: queue_url, message_handler: ExampleMessageHandler).handle('message', 'metadata')
|
113
|
+
described_class.new(queue_url: queue_url, message_handler: ExampleMessageHandler).handle('message', 'metadata', 'message_attributes')
|
112
114
|
expect(mock_handler).to have_received(:handle).once
|
113
115
|
end
|
114
116
|
end
|
@@ -117,12 +119,12 @@ describe Pheme::QueuePoller do
|
|
117
119
|
it 'uses handler when given one' do
|
118
120
|
mock_handler = spy('MessageHandler')
|
119
121
|
|
120
|
-
poller = described_class.new(queue_url: queue_url) do |message, metadata|
|
121
|
-
mock_handler.process(message, metadata)
|
122
|
+
poller = described_class.new(queue_url: queue_url) do |message, metadata, message_attributes|
|
123
|
+
mock_handler.process(message, metadata, message_attributes)
|
122
124
|
end
|
123
|
-
poller.handle('message', 'metadata')
|
125
|
+
poller.handle('message', 'metadata', 'message_attributes')
|
124
126
|
|
125
|
-
expect(mock_handler).to have_received(:process).with('message', 'metadata').once
|
127
|
+
expect(mock_handler).to have_received(:process).with('message', 'metadata', 'message_attributes').once
|
126
128
|
end
|
127
129
|
|
128
130
|
it 'fails on invalid handler' do
|
@@ -134,6 +136,63 @@ describe Pheme::QueuePoller do
|
|
134
136
|
end
|
135
137
|
end
|
136
138
|
|
139
|
+
describe '#parse_message_attributes' do
|
140
|
+
subject { described_class.new(queue_url: queue_url).parse_message_attributes(queue_message) }
|
141
|
+
|
142
|
+
context 'when no message_attributes' do
|
143
|
+
it { is_expected.to eq({}) }
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'when message attributes' do
|
147
|
+
let(:queue_message) do
|
148
|
+
OpenStruct.new(
|
149
|
+
body: { Message: message }.to_json,
|
150
|
+
message_id: message_id,
|
151
|
+
message_attributes: {
|
152
|
+
"key" => {
|
153
|
+
"data_type" => data_type,
|
154
|
+
"string_value" => string_value,
|
155
|
+
},
|
156
|
+
},
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'when data_type is String' do
|
161
|
+
let(:data_type) { 'String' }
|
162
|
+
let(:string_value) { 'some-string-value' }
|
163
|
+
let(:expected_value) { 'some-string-value' }
|
164
|
+
|
165
|
+
its([:key]) { is_expected.to eq(expected_value) }
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'when data_type is Number' do
|
169
|
+
let(:data_type) { 'Number' }
|
170
|
+
|
171
|
+
context 'and it is an int' do
|
172
|
+
let(:string_value) { '1' }
|
173
|
+
let(:expected_value) { 1 }
|
174
|
+
|
175
|
+
its([:key]) { is_expected.to eq(expected_value) }
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'and it is a float' do
|
179
|
+
let(:string_value) { '1.5' }
|
180
|
+
let(:expected_value) { 1.5 }
|
181
|
+
|
182
|
+
its([:key]) { is_expected.to eq(expected_value) }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context 'when data_type is String.array' do
|
187
|
+
let(:data_type) { 'String.Array' }
|
188
|
+
let(:string_value) { '["sdfsdf",1,2,null,true,false]' }
|
189
|
+
let(:expected_value) { ["sdfsdf", 1, 2, nil, true, false] }
|
190
|
+
|
191
|
+
its([:key]) { is_expected.to eq(expected_value) }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
137
196
|
describe "#parse_body" do
|
138
197
|
subject { poller.parse_body(queue_message) }
|
139
198
|
|
@@ -305,6 +364,7 @@ describe Pheme::QueuePoller do
|
|
305
364
|
expect(ExampleMessageHandler).to receive(:new).with(
|
306
365
|
message: RecursiveOpenStruct.new(message),
|
307
366
|
metadata: { timestamp: timestamp, topic_arn: topic_arn },
|
367
|
+
message_attributes: {},
|
308
368
|
)
|
309
369
|
subject.poll
|
310
370
|
end
|
@@ -3,10 +3,10 @@ class ExampleQueuePoller < Pheme::QueuePoller
|
|
3
3
|
super(queue_url: queue_url, **kwargs)
|
4
4
|
end
|
5
5
|
|
6
|
-
def handle(message, metadata)
|
6
|
+
def handle(message, metadata, message_attributes)
|
7
7
|
case message.status
|
8
8
|
when 'complete', 'rejected'
|
9
|
-
ExampleMessageHandler.new(message: message, metadata: metadata).handle
|
9
|
+
ExampleMessageHandler.new(message: message, metadata: metadata, message_attributes: message_attributes).handle
|
10
10
|
else
|
11
11
|
raise ArgumentError, "Unknown message status: #{message.status}"
|
12
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pheme
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Graham
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -98,16 +98,16 @@ dependencies:
|
|
98
98
|
name: coveralls
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
103
|
+
version: '0.8'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
110
|
+
version: '0.8'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: git
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|