deimos-ruby 1.24.2 → 2.0.0.pre.alpha1
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_todo.yml +0 -17
- data/.tool-versions +1 -0
- data/CHANGELOG.md +5 -0
- data/README.md +287 -498
- data/deimos-ruby.gemspec +4 -4
- data/docs/CONFIGURATION.md +133 -226
- data/docs/UPGRADING.md +237 -0
- data/lib/deimos/active_record_consume/batch_consumption.rb +29 -28
- data/lib/deimos/active_record_consume/mass_updater.rb +59 -4
- data/lib/deimos/active_record_consume/message_consumption.rb +15 -21
- data/lib/deimos/active_record_consumer.rb +36 -21
- data/lib/deimos/active_record_producer.rb +28 -9
- data/lib/deimos/backends/base.rb +4 -35
- data/lib/deimos/backends/kafka.rb +6 -22
- data/lib/deimos/backends/kafka_async.rb +6 -22
- data/lib/deimos/backends/{db.rb → outbox.rb} +13 -9
- data/lib/deimos/config/configuration.rb +116 -379
- data/lib/deimos/consume/batch_consumption.rb +24 -124
- data/lib/deimos/consume/message_consumption.rb +36 -63
- data/lib/deimos/consumer.rb +16 -75
- data/lib/deimos/ext/consumer_route.rb +35 -0
- data/lib/deimos/ext/producer_middleware.rb +94 -0
- data/lib/deimos/ext/producer_route.rb +22 -0
- data/lib/deimos/ext/redraw.rb +29 -0
- data/lib/deimos/ext/routing_defaults.rb +72 -0
- data/lib/deimos/ext/schema_route.rb +70 -0
- data/lib/deimos/kafka_message.rb +2 -2
- data/lib/deimos/kafka_source.rb +2 -7
- data/lib/deimos/kafka_topic_info.rb +1 -1
- data/lib/deimos/logging.rb +71 -0
- data/lib/deimos/message.rb +2 -11
- data/lib/deimos/metrics/datadog.rb +40 -1
- data/lib/deimos/metrics/provider.rb +4 -4
- data/lib/deimos/producer.rb +39 -116
- data/lib/deimos/railtie.rb +6 -0
- data/lib/deimos/schema_backends/avro_base.rb +21 -21
- data/lib/deimos/schema_backends/avro_schema_registry.rb +1 -2
- data/lib/deimos/schema_backends/avro_validation.rb +2 -2
- data/lib/deimos/schema_backends/base.rb +19 -12
- data/lib/deimos/schema_backends/mock.rb +6 -1
- data/lib/deimos/schema_backends/plain.rb +47 -0
- data/lib/deimos/schema_class/base.rb +2 -2
- data/lib/deimos/schema_class/enum.rb +1 -1
- data/lib/deimos/schema_class/record.rb +2 -2
- data/lib/deimos/test_helpers.rb +95 -320
- data/lib/deimos/tracing/provider.rb +6 -6
- data/lib/deimos/transcoder.rb +88 -0
- data/lib/deimos/utils/db_poller/base.rb +16 -14
- data/lib/deimos/utils/db_poller/state_based.rb +3 -3
- data/lib/deimos/utils/db_poller/time_based.rb +4 -4
- data/lib/deimos/utils/db_poller.rb +1 -1
- data/lib/deimos/utils/deadlock_retry.rb +1 -1
- data/lib/deimos/utils/{db_producer.rb → outbox_producer.rb} +16 -47
- data/lib/deimos/utils/schema_class.rb +0 -7
- data/lib/deimos/version.rb +1 -1
- data/lib/deimos.rb +79 -26
- data/lib/generators/deimos/{db_backend_generator.rb → outbox_backend_generator.rb} +4 -4
- data/lib/generators/deimos/schema_class_generator.rb +0 -1
- data/lib/generators/deimos/v2/templates/karafka.rb.tt +149 -0
- data/lib/generators/deimos/v2_generator.rb +193 -0
- data/lib/tasks/deimos.rake +5 -7
- data/spec/active_record_batch_consumer_association_spec.rb +22 -13
- data/spec/active_record_batch_consumer_spec.rb +84 -65
- data/spec/active_record_consume/batch_consumption_spec.rb +10 -10
- data/spec/active_record_consume/batch_slicer_spec.rb +12 -12
- data/spec/active_record_consume/mass_updater_spec.rb +137 -0
- data/spec/active_record_consumer_spec.rb +29 -13
- data/spec/active_record_producer_spec.rb +36 -26
- data/spec/backends/base_spec.rb +0 -23
- data/spec/backends/kafka_async_spec.rb +1 -3
- data/spec/backends/kafka_spec.rb +1 -3
- data/spec/backends/{db_spec.rb → outbox_spec.rb} +14 -20
- data/spec/batch_consumer_spec.rb +66 -116
- data/spec/consumer_spec.rb +53 -147
- data/spec/deimos_spec.rb +10 -126
- data/spec/kafka_source_spec.rb +19 -52
- data/spec/karafka/karafka.rb +69 -0
- data/spec/karafka_config/karafka_spec.rb +97 -0
- data/spec/logging_spec.rb +25 -0
- data/spec/message_spec.rb +9 -9
- data/spec/producer_spec.rb +112 -254
- data/spec/rake_spec.rb +1 -3
- data/spec/schema_backends/avro_validation_spec.rb +1 -1
- data/spec/schemas/com/my-namespace/MySchemaWithTitle.avsc +22 -0
- data/spec/snapshots/consumers-no-nest.snap +49 -0
- data/spec/snapshots/consumers.snap +49 -0
- data/spec/snapshots/consumers_and_producers-no-nest.snap +49 -0
- data/spec/snapshots/consumers_and_producers.snap +49 -0
- data/spec/snapshots/consumers_circular-no-nest.snap +49 -0
- data/spec/snapshots/consumers_circular.snap +49 -0
- data/spec/snapshots/consumers_complex_types-no-nest.snap +49 -0
- data/spec/snapshots/consumers_complex_types.snap +49 -0
- data/spec/snapshots/consumers_nested-no-nest.snap +49 -0
- data/spec/snapshots/consumers_nested.snap +49 -0
- data/spec/snapshots/namespace_folders.snap +49 -0
- data/spec/snapshots/namespace_map.snap +49 -0
- data/spec/snapshots/producers_with_key-no-nest.snap +49 -0
- data/spec/snapshots/producers_with_key.snap +49 -0
- data/spec/spec_helper.rb +61 -29
- data/spec/utils/db_poller_spec.rb +49 -39
- data/spec/utils/{db_producer_spec.rb → outbox_producer_spec.rb} +17 -184
- metadata +58 -67
- data/lib/deimos/batch_consumer.rb +0 -7
- data/lib/deimos/config/phobos_config.rb +0 -163
- data/lib/deimos/instrumentation.rb +0 -95
- data/lib/deimos/monkey_patches/phobos_cli.rb +0 -35
- data/lib/deimos/utils/inline_consumer.rb +0 -158
- data/lib/deimos/utils/lag_reporter.rb +0 -186
- data/lib/deimos/utils/schema_controller_mixin.rb +0 -129
- data/spec/config/configuration_spec.rb +0 -321
- data/spec/kafka_listener_spec.rb +0 -55
- data/spec/phobos.bad_db.yml +0 -73
- data/spec/phobos.yml +0 -77
- data/spec/utils/inline_consumer_spec.rb +0 -31
- data/spec/utils/lag_reporter_spec.rb +0 -76
- data/spec/utils/platform_schema_validation_spec.rb +0 -0
- data/spec/utils/schema_controller_mixin_spec.rb +0 -84
- /data/lib/generators/deimos/{db_backend → outbox_backend}/templates/migration +0 -0
- /data/lib/generators/deimos/{db_backend → outbox_backend}/templates/rails3_migration +0 -0
data/spec/batch_consumer_spec.rb
CHANGED
@@ -3,19 +3,34 @@
|
|
3
3
|
# :nodoc:
|
4
4
|
module ConsumerTest
|
5
5
|
describe Deimos::Consumer, 'Batch Consumer' do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
let(:schema) { 'MySchema' }
|
7
|
+
let(:use_schema_classes) { false }
|
8
|
+
let(:reraise_errors) { false }
|
9
|
+
let(:key_config) { { field: 'test_id' } }
|
10
|
+
let(:consumer_class) do
|
11
|
+
Class.new(described_class) do
|
13
12
|
# :nodoc:
|
14
|
-
def consume_batch
|
15
|
-
raise 'This should not be called unless call_original is set'
|
13
|
+
def consume_batch
|
16
14
|
end
|
17
15
|
end
|
16
|
+
end
|
17
|
+
before(:each) do
|
18
|
+
# :nodoc:
|
19
|
+
stub_const('MyBatchConsumer', consumer_class)
|
18
20
|
stub_const('ConsumerTest::MyBatchConsumer', consumer_class)
|
21
|
+
klass = consumer_class
|
22
|
+
route_schema = schema
|
23
|
+
route_key = key_config
|
24
|
+
route_use_classes = use_schema_classes
|
25
|
+
Karafka::App.routes.redraw do
|
26
|
+
topic 'my-topic' do
|
27
|
+
consumer klass
|
28
|
+
schema route_schema
|
29
|
+
namespace 'com.my-namespace'
|
30
|
+
key_config route_key
|
31
|
+
use_schema_classes route_use_classes
|
32
|
+
end
|
33
|
+
end
|
19
34
|
end
|
20
35
|
|
21
36
|
let(:batch) do
|
@@ -38,41 +53,23 @@ module ConsumerTest
|
|
38
53
|
Deimos::Utils::SchemaClass.instance(p, 'MySchema', 'com.my-namespace')
|
39
54
|
end
|
40
55
|
end
|
56
|
+
let(:use_schema_classes) { true }
|
41
57
|
|
42
58
|
before(:each) do
|
43
59
|
Deimos.configure do |config|
|
44
|
-
config.schema.use_schema_classes = use_schema_classes
|
45
60
|
config.schema.use_full_namespace = true
|
46
61
|
end
|
47
62
|
end
|
48
63
|
|
49
|
-
it 'should provide backwards compatibility for BatchConsumer class' do
|
50
|
-
consumer_class = Class.new(Deimos::BatchConsumer) do
|
51
|
-
schema 'MySchema'
|
52
|
-
namespace 'com.my-namespace'
|
53
|
-
key_config field: 'test_id'
|
54
|
-
|
55
|
-
# :nodoc:
|
56
|
-
def consume_batch(_payloads, _metadata)
|
57
|
-
raise 'This should not be called unless call_original is set'
|
58
|
-
end
|
59
|
-
end
|
60
|
-
stub_const('ConsumerTest::MyOldBatchConsumer', consumer_class)
|
61
|
-
|
62
|
-
test_consume_batch(MyOldBatchConsumer, schema_class_batch) do |received, _metadata|
|
63
|
-
expect(received).to eq(schema_class_batch)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
64
|
it 'should consume a batch of messages' do
|
68
|
-
test_consume_batch(MyBatchConsumer, schema_class_batch) do |received
|
69
|
-
expect(received).to eq(schema_class_batch)
|
65
|
+
test_consume_batch(MyBatchConsumer, schema_class_batch) do |received|
|
66
|
+
expect(received.payloads).to eq(schema_class_batch)
|
70
67
|
end
|
71
68
|
end
|
72
69
|
|
73
70
|
it 'should consume a message on a topic' do
|
74
|
-
test_consume_batch('
|
75
|
-
expect(received).to eq(schema_class_batch)
|
71
|
+
test_consume_batch('my-topic', schema_class_batch) do |received|
|
72
|
+
expect(received.payloads).to eq(schema_class_batch)
|
76
73
|
end
|
77
74
|
end
|
78
75
|
end
|
@@ -80,29 +77,19 @@ module ConsumerTest
|
|
80
77
|
end
|
81
78
|
|
82
79
|
describe 'when reraising errors is disabled' do
|
83
|
-
|
84
|
-
Deimos.configure { |config| config.consumers.reraise_errors = false }
|
85
|
-
end
|
80
|
+
let(:reraise_errors) { false }
|
86
81
|
|
87
82
|
it 'should not fail when before_consume_batch fails' do
|
88
83
|
expect {
|
89
84
|
test_consume_batch(
|
90
85
|
MyBatchConsumer,
|
91
|
-
batch
|
92
|
-
|
93
|
-
|
86
|
+
batch
|
87
|
+
) do
|
88
|
+
raise 'OH NOES'
|
89
|
+
end
|
94
90
|
}.not_to raise_error
|
95
91
|
end
|
96
92
|
|
97
|
-
it 'should not fail when consume_batch fails' do
|
98
|
-
expect {
|
99
|
-
test_consume_batch(
|
100
|
-
MyBatchConsumer,
|
101
|
-
invalid_payloads,
|
102
|
-
skip_expectation: true
|
103
|
-
)
|
104
|
-
}.not_to raise_error
|
105
|
-
end
|
106
93
|
end
|
107
94
|
|
108
95
|
describe 'decoding' do
|
@@ -111,53 +98,32 @@ module ConsumerTest
|
|
111
98
|
end
|
112
99
|
|
113
100
|
it 'should decode payloads for all messages in the batch' do
|
114
|
-
test_consume_batch('
|
101
|
+
test_consume_batch('my-topic', batch) do
|
115
102
|
# Mock decoder simply returns the payload
|
116
|
-
expect(
|
103
|
+
expect(messages.payloads).to eq(batch)
|
117
104
|
end
|
118
105
|
end
|
119
106
|
|
120
107
|
it 'should decode keys for all messages in the batch' do
|
121
|
-
|
122
|
-
|
123
|
-
expect_any_instance_of(ConsumerTest::MyBatchConsumer).
|
124
|
-
to receive(:decode_key).with(keys[1]).and_call_original
|
125
|
-
|
126
|
-
test_consume_batch('my_batch_consume_topic', batch, keys: keys) do |_received, metadata|
|
127
|
-
# Mock decode_key extracts the value of the first field as the key
|
128
|
-
expect(metadata[:keys]).to eq(%w(foo bar))
|
129
|
-
expect(metadata[:first_offset]).to eq(1)
|
108
|
+
test_consume_batch('my-topic', batch, keys: keys) do
|
109
|
+
expect(messages.map(&:key)).to eq([{'test_id' => 'foo'}, {'test_id' => 'bar'}])
|
130
110
|
end
|
131
111
|
end
|
132
112
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
stub_const('ConsumerTest::MyBatchConsumer', consumer_class)
|
140
|
-
|
141
|
-
test_consume_batch('my_batch_consume_topic', batch, keys: [1, 2]) do |_received, metadata|
|
142
|
-
expect(metadata[:keys]).to eq([1, 2])
|
113
|
+
context 'with plain keys' do
|
114
|
+
let(:key_config) { { plain: true } }
|
115
|
+
it 'should decode plain keys for all messages in the batch' do
|
116
|
+
test_consume_batch('my-topic', batch, keys: [1, 2]) do |_received, metadata|
|
117
|
+
expect(metadata[:keys]).to eq([1, 2])
|
118
|
+
end
|
143
119
|
end
|
144
120
|
end
|
145
121
|
end
|
146
122
|
|
147
123
|
describe 'timestamps' do
|
124
|
+
let(:schema) { 'MySchemaWithDateTimes' }
|
125
|
+
let(:key_config) { { none: true } }
|
148
126
|
before(:each) do
|
149
|
-
# :nodoc:
|
150
|
-
consumer_class = Class.new(described_class) do
|
151
|
-
schema 'MySchemaWithDateTimes'
|
152
|
-
namespace 'com.my-namespace'
|
153
|
-
key_config plain: true
|
154
|
-
|
155
|
-
# :nodoc:
|
156
|
-
def consume_batch(_payloads, _metadata)
|
157
|
-
raise 'This should not be called unless call_original is set'
|
158
|
-
end
|
159
|
-
end
|
160
|
-
stub_const('ConsumerTest::MyBatchConsumer', consumer_class)
|
161
127
|
allow(Deimos.config.metrics).to receive(:histogram)
|
162
128
|
end
|
163
129
|
|
@@ -202,45 +168,36 @@ module ConsumerTest
|
|
202
168
|
end
|
203
169
|
|
204
170
|
it 'should consume a batch' do
|
205
|
-
expect(Deimos.config.metrics).
|
206
|
-
|
207
|
-
|
208
|
-
|
171
|
+
# expect(Deimos.config.metrics).
|
172
|
+
# to receive(:histogram).with('handler',
|
173
|
+
# a_kind_of(Numeric),
|
174
|
+
# tags: %w(time:time_delayed topic:my-topic)).twice
|
209
175
|
|
210
|
-
test_consume_batch('
|
211
|
-
expect(
|
176
|
+
test_consume_batch('my-topic', batch_with_time) do
|
177
|
+
expect(messages.payloads).to eq(batch_with_time)
|
212
178
|
end
|
213
179
|
end
|
214
180
|
|
215
181
|
it 'should fail nicely and ignore timestamps with the wrong format' do
|
216
182
|
batch = invalid_times.concat(batch_with_time)
|
217
183
|
|
218
|
-
expect(Deimos.config.metrics).
|
219
|
-
|
220
|
-
|
221
|
-
|
184
|
+
# expect(Deimos.config.metrics).
|
185
|
+
# to receive(:histogram).with('handler',
|
186
|
+
# a_kind_of(Numeric),
|
187
|
+
# tags: %w(time:time_delayed topic:my-topic)).twice
|
222
188
|
|
223
|
-
test_consume_batch('
|
224
|
-
expect(
|
189
|
+
test_consume_batch('my-topic', batch) do
|
190
|
+
expect(messages.payloads).to eq(batch)
|
225
191
|
end
|
226
192
|
end
|
227
193
|
end
|
228
194
|
|
229
195
|
describe 'logging' do
|
196
|
+
let(:schema) { 'MySchemaWithUniqueId' }
|
197
|
+
let(:key_config) { { plain: true } }
|
230
198
|
before(:each) do
|
231
|
-
# :nodoc:
|
232
|
-
consumer_class = Class.new(described_class) do
|
233
|
-
schema 'MySchemaWithUniqueId'
|
234
|
-
namespace 'com.my-namespace'
|
235
|
-
key_config plain: true
|
236
|
-
|
237
|
-
# :nodoc:
|
238
|
-
def consume_batch(_payloads, _metadata)
|
239
|
-
raise 'This should not be called unless call_original is set'
|
240
|
-
end
|
241
|
-
end
|
242
|
-
stub_const('ConsumerTest::MyBatchConsumer', consumer_class)
|
243
199
|
allow(Deimos.config.metrics).to receive(:histogram)
|
200
|
+
set_karafka_config(:payload_log, :keys)
|
244
201
|
end
|
245
202
|
|
246
203
|
it 'should log message identifiers' do
|
@@ -251,20 +208,13 @@ module ConsumerTest
|
|
251
208
|
'timestamp' => 2.minutes.ago.to_s, 'message_id' => 'two' }
|
252
209
|
]
|
253
210
|
|
254
|
-
allow(Deimos.
|
255
|
-
to receive(:info)
|
211
|
+
allow(Deimos::Logging).to receive(:log_info)
|
256
212
|
|
257
|
-
expect(Deimos
|
258
|
-
to receive(:
|
259
|
-
with(hash_including(
|
260
|
-
message_ids: [
|
261
|
-
{ key: 1, message_id: 'one' },
|
262
|
-
{ key: 2, message_id: 'two' }
|
263
|
-
]
|
264
|
-
)).
|
265
|
-
twice
|
213
|
+
expect(Deimos::Logging).
|
214
|
+
to receive(:log_info).
|
215
|
+
with(hash_including(payload_keys: ["1", "2"]))
|
266
216
|
|
267
|
-
test_consume_batch('
|
217
|
+
test_consume_batch('my-topic', batch_with_message_id, keys: [1, 2])
|
268
218
|
end
|
269
219
|
end
|
270
220
|
end
|
data/spec/consumer_spec.rb
CHANGED
@@ -4,33 +4,44 @@
|
|
4
4
|
# rubocop:disable Metrics/ModuleLength
|
5
5
|
module ConsumerTest
|
6
6
|
describe Deimos::Consumer, 'Message Consumer' do
|
7
|
+
let(:use_schema_classes) { false }
|
8
|
+
let(:reraise_errors) { false }
|
7
9
|
prepend_before(:each) do
|
8
10
|
# :nodoc:
|
9
11
|
consumer_class = Class.new(described_class) do
|
10
|
-
schema 'MySchema'
|
11
|
-
namespace 'com.my-namespace'
|
12
|
-
key_config field: 'test_id'
|
13
12
|
|
14
13
|
# :nodoc:
|
15
|
-
def fatal_error?(_exception,
|
16
|
-
|
14
|
+
def fatal_error?(_exception, messages)
|
15
|
+
messages.payloads.first&.dig(:test_id) == ['fatal']
|
17
16
|
end
|
18
17
|
|
19
18
|
# :nodoc:
|
20
|
-
def
|
21
|
-
|
19
|
+
def consume_message(message)
|
20
|
+
message.payload
|
22
21
|
end
|
23
22
|
end
|
24
23
|
stub_const('ConsumerTest::MyConsumer', consumer_class)
|
24
|
+
route_usc = use_schema_classes
|
25
|
+
route_rre = reraise_errors
|
26
|
+
Karafka::App.routes.redraw do
|
27
|
+
topic 'my_consume_topic' do
|
28
|
+
schema 'MySchema'
|
29
|
+
namespace 'com.my-namespace'
|
30
|
+
key_config field: 'test_id'
|
31
|
+
consumer consumer_class
|
32
|
+
use_schema_classes route_usc
|
33
|
+
reraise_errors route_rre
|
34
|
+
end
|
35
|
+
end
|
25
36
|
end
|
26
37
|
|
27
38
|
describe 'consume' do
|
28
39
|
SCHEMA_CLASS_SETTINGS.each do |setting, use_schema_classes|
|
40
|
+
let(:use_schema_classes) { use_schema_classes }
|
29
41
|
context "with Schema Class consumption #{setting}" do
|
30
42
|
|
31
43
|
before(:each) do
|
32
44
|
Deimos.configure do |config|
|
33
|
-
config.schema.use_schema_classes = use_schema_classes
|
34
45
|
config.schema.use_full_namespace = true
|
35
46
|
end
|
36
47
|
end
|
@@ -45,26 +56,9 @@ module ConsumerTest
|
|
45
56
|
end
|
46
57
|
|
47
58
|
it 'should consume a nil message' do
|
48
|
-
test_consume_message(MyConsumer, nil) do
|
49
|
-
expect(
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'should consume a message idempotently' do
|
54
|
-
# testing for a crash and re-consuming the same message/metadata
|
55
|
-
key = { 'test_id' => 'foo' }
|
56
|
-
test_metadata = { key: key }
|
57
|
-
allow_any_instance_of(MyConsumer).to(receive(:decode_key)) do |_instance, k|
|
58
|
-
k['test_id']
|
59
|
+
test_consume_message(MyConsumer, nil, key: 'foo') do
|
60
|
+
expect(messages).to be_empty
|
59
61
|
end
|
60
|
-
MyConsumer.new.around_consume({ 'test_id' => 'foo',
|
61
|
-
'some_int' => 123 }, test_metadata) do |_payload, metadata|
|
62
|
-
expect(metadata[:key]).to eq('foo')
|
63
|
-
end
|
64
|
-
MyConsumer.new.around_consume({ 'test_id' => 'foo',
|
65
|
-
'some_int' => 123 }, test_metadata) do |_payload, metadata|
|
66
|
-
expect(metadata[:key]).to eq('foo')
|
67
|
-
end
|
68
62
|
end
|
69
63
|
|
70
64
|
it 'should consume a message on a topic' do
|
@@ -77,83 +71,82 @@ module ConsumerTest
|
|
77
71
|
end
|
78
72
|
|
79
73
|
it 'should fail on invalid message' do
|
80
|
-
|
74
|
+
expect { test_consume_message(MyConsumer, { 'invalid' => 'key' }) }.
|
75
|
+
to raise_error(Avro::SchemaValidator::ValidationError)
|
81
76
|
end
|
82
77
|
|
83
78
|
it 'should fail if reraise is false but fatal_error is true' do
|
84
|
-
|
85
|
-
|
79
|
+
expect { test_consume_message(MyConsumer, {test_id: 'fatal'}) }.
|
80
|
+
to raise_error(Avro::SchemaValidator::ValidationError)
|
86
81
|
end
|
87
82
|
|
88
83
|
it 'should fail if fatal_error is true globally' do
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
end
|
93
|
-
test_consume_invalid_message(MyConsumer, { 'invalid' => 'key' })
|
84
|
+
set_karafka_config(:fatal_error, proc { true })
|
85
|
+
expect { test_consume_message(MyConsumer, { 'invalid' => 'key' }) }.
|
86
|
+
to raise_error(Avro::SchemaValidator::ValidationError)
|
94
87
|
end
|
95
88
|
|
96
89
|
it 'should fail on message with extra fields' do
|
97
|
-
|
90
|
+
allow_any_instance_of(Deimos::SchemaBackends::AvroValidation).
|
91
|
+
to receive(:coerce) { |_, m| m.with_indifferent_access }
|
92
|
+
expect { test_consume_message(MyConsumer,
|
98
93
|
{ 'test_id' => 'foo',
|
99
94
|
'some_int' => 123,
|
100
|
-
'extra_field' => 'field name' })
|
95
|
+
'extra_field' => 'field name' }) }.
|
96
|
+
to raise_error(Avro::SchemaValidator::ValidationError)
|
101
97
|
end
|
102
98
|
|
103
99
|
it 'should not fail when before_consume fails without reraising errors' do
|
104
|
-
|
100
|
+
set_karafka_config(:reraise_errors, false)
|
105
101
|
expect {
|
106
102
|
test_consume_message(
|
107
103
|
MyConsumer,
|
108
104
|
{ 'test_id' => 'foo',
|
109
|
-
'some_int' => 123 }
|
110
|
-
skip_expectation: true
|
111
|
-
) { raise 'OH NOES' }
|
105
|
+
'some_int' => 123 }) { raise 'OH NOES' }
|
112
106
|
}.not_to raise_error
|
113
107
|
end
|
114
108
|
|
115
109
|
it 'should not fail when consume fails without reraising errors' do
|
116
|
-
|
110
|
+
set_karafka_config(:reraise_errors, false)
|
111
|
+
allow(Deimos::ProducerMiddleware).to receive(:call) { |m| m[:payload] = m[:payload].to_json; m }
|
117
112
|
expect {
|
118
113
|
test_consume_message(
|
119
114
|
MyConsumer,
|
120
|
-
{ 'invalid' => 'key' }
|
121
|
-
skip_expectation: true
|
122
|
-
)
|
115
|
+
{ 'invalid' => 'key' })
|
123
116
|
}.not_to raise_error
|
124
117
|
end
|
125
|
-
|
126
|
-
it 'should call original' do
|
127
|
-
expect {
|
128
|
-
test_consume_message(MyConsumer,
|
129
|
-
{ 'test_id' => 'foo', 'some_int' => 123 },
|
130
|
-
call_original: true)
|
131
|
-
}.to raise_error('This should not be called unless call_original is set')
|
132
|
-
end
|
133
118
|
end
|
134
119
|
end
|
135
120
|
|
136
121
|
context 'with overriden schema classes' do
|
137
122
|
|
138
123
|
before(:each) do
|
124
|
+
set_karafka_config(:use_schema_classes, true)
|
139
125
|
Deimos.configure do |config|
|
140
|
-
config.schema.use_schema_classes = true
|
141
126
|
config.schema.use_full_namespace = true
|
142
127
|
end
|
143
128
|
end
|
144
129
|
|
145
130
|
prepend_before(:each) do
|
146
131
|
consumer_class = Class.new(described_class) do
|
147
|
-
schema 'MyUpdatedSchema'
|
148
|
-
namespace 'com.my-namespace'
|
149
|
-
key_config field: 'test_id'
|
150
|
-
|
151
132
|
# :nodoc:
|
152
|
-
def
|
153
|
-
|
133
|
+
def consume_message(message)
|
134
|
+
message.payload
|
154
135
|
end
|
155
136
|
end
|
156
137
|
stub_const('ConsumerTest::MyConsumer', consumer_class)
|
138
|
+
Deimos.config.schema.use_schema_classes = true
|
139
|
+
Karafka::App.routes.redraw do
|
140
|
+
topic 'my_consume_topic' do
|
141
|
+
schema 'MyUpdatedSchema'
|
142
|
+
namespace 'com.my-namespace'
|
143
|
+
key_config field: 'test_id'
|
144
|
+
consumer consumer_class
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
after(:each) do
|
149
|
+
Karafka::App.routes.clear
|
157
150
|
end
|
158
151
|
|
159
152
|
it 'should consume messages' do
|
@@ -169,93 +162,6 @@ module ConsumerTest
|
|
169
162
|
end
|
170
163
|
end
|
171
164
|
|
172
|
-
describe 'decode_key' do
|
173
|
-
|
174
|
-
it 'should use the key field in the value if set' do
|
175
|
-
# actual decoding is disabled in test
|
176
|
-
expect(MyConsumer.new.decode_key('test_id' => '123')).to eq('123')
|
177
|
-
expect { MyConsumer.new.decode_key(123) }.to raise_error(NoMethodError)
|
178
|
-
end
|
179
|
-
|
180
|
-
it 'should use the key schema if set' do
|
181
|
-
consumer_class = Class.new(described_class) do
|
182
|
-
schema 'MySchema'
|
183
|
-
namespace 'com.my-namespace'
|
184
|
-
key_config schema: 'MySchema_key'
|
185
|
-
end
|
186
|
-
stub_const('ConsumerTest::MySchemaConsumer', consumer_class)
|
187
|
-
expect(MyConsumer.new.decode_key('test_id' => '123')).to eq('123')
|
188
|
-
expect { MyConsumer.new.decode_key(123) }.to raise_error(NoMethodError)
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'should not decode if plain is set' do
|
192
|
-
consumer_class = Class.new(described_class) do
|
193
|
-
schema 'MySchema'
|
194
|
-
namespace 'com.my-namespace'
|
195
|
-
key_config plain: true
|
196
|
-
end
|
197
|
-
stub_const('ConsumerTest::MyNonEncodedConsumer', consumer_class)
|
198
|
-
expect(MyNonEncodedConsumer.new.decode_key('123')).to eq('123')
|
199
|
-
end
|
200
|
-
|
201
|
-
it 'should error with nothing set' do
|
202
|
-
consumer_class = Class.new(described_class) do
|
203
|
-
schema 'MySchema'
|
204
|
-
namespace 'com.my-namespace'
|
205
|
-
end
|
206
|
-
stub_const('ConsumerTest::MyErrorConsumer', consumer_class)
|
207
|
-
expect { MyErrorConsumer.new.decode_key('123') }.
|
208
|
-
to raise_error('No key config given - if you are not decoding keys, please use `key_config plain: true`')
|
209
|
-
end
|
210
|
-
|
211
|
-
end
|
212
|
-
|
213
|
-
describe 'timestamps' do
|
214
|
-
before(:each) do
|
215
|
-
# :nodoc:
|
216
|
-
consumer_class = Class.new(described_class) do
|
217
|
-
schema 'MySchemaWithDateTimes'
|
218
|
-
namespace 'com.my-namespace'
|
219
|
-
key_config plain: true
|
220
|
-
|
221
|
-
# :nodoc:
|
222
|
-
def consume(_payload, _metadata)
|
223
|
-
raise 'This should not be called unless call_original is set'
|
224
|
-
end
|
225
|
-
end
|
226
|
-
stub_const('ConsumerTest::MyConsumer', consumer_class)
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'should consume a message' do
|
230
|
-
expect(Deimos.config.metrics).to receive(:histogram).twice
|
231
|
-
test_consume_message('my_consume_topic',
|
232
|
-
{ 'test_id' => 'foo',
|
233
|
-
'some_int' => 123,
|
234
|
-
'updated_at' => Time.now.to_i,
|
235
|
-
'timestamp' => 2.minutes.ago.to_s }) do |payload, _metadata|
|
236
|
-
expect(payload['test_id']).to eq('foo')
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
it 'should fail nicely when timestamp wrong format' do
|
241
|
-
expect(Deimos.config.metrics).to receive(:histogram).twice
|
242
|
-
test_consume_message('my_consume_topic',
|
243
|
-
{ 'test_id' => 'foo',
|
244
|
-
'some_int' => 123,
|
245
|
-
'updated_at' => Time.now.to_i,
|
246
|
-
'timestamp' => 'dffdf' }) do |payload, _metadata|
|
247
|
-
expect(payload['test_id']).to eq('foo')
|
248
|
-
end
|
249
|
-
test_consume_message('my_consume_topic',
|
250
|
-
{ 'test_id' => 'foo',
|
251
|
-
'some_int' => 123,
|
252
|
-
'updated_at' => Time.now.to_i,
|
253
|
-
'timestamp' => '' }) do |payload, _metadata|
|
254
|
-
expect(payload['test_id']).to eq('foo')
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
end
|
259
165
|
end
|
260
166
|
end
|
261
167
|
# rubocop:enable Metrics/ModuleLength
|