deimos-ruby 1.24.3 → 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 +1 -1
- data/README.md +287 -498
- data/deimos-ruby.gemspec +4 -4
- data/docs/CONFIGURATION.md +133 -227
- data/docs/UPGRADING.md +237 -0
- data/lib/deimos/active_record_consume/batch_consumption.rb +28 -29
- data/lib/deimos/active_record_consume/message_consumption.rb +15 -21
- data/lib/deimos/active_record_consumer.rb +36 -26
- 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 -385
- 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_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 -164
- 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 -329
- 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
|
@@ -4,12 +4,12 @@ RSpec.describe Deimos::ActiveRecordConsume::BatchSlicer do
|
|
|
4
4
|
describe '#slice' do
|
|
5
5
|
let(:batch) do
|
|
6
6
|
[
|
|
7
|
-
Deimos::Message.new({ v: 1 },
|
|
8
|
-
Deimos::Message.new({ v: 123 },
|
|
9
|
-
Deimos::Message.new({ v: 999 },
|
|
10
|
-
Deimos::Message.new({ v: 456 },
|
|
11
|
-
Deimos::Message.new({ v: 2 },
|
|
12
|
-
Deimos::Message.new({ v: 3 },
|
|
7
|
+
Deimos::Message.new({ v: 1 }, key: 'C'),
|
|
8
|
+
Deimos::Message.new({ v: 123 }, key: 'A'),
|
|
9
|
+
Deimos::Message.new({ v: 999 }, key: 'B'),
|
|
10
|
+
Deimos::Message.new({ v: 456 }, key: 'A'),
|
|
11
|
+
Deimos::Message.new({ v: 2 }, key: 'C'),
|
|
12
|
+
Deimos::Message.new({ v: 3 }, key: 'C')
|
|
13
13
|
]
|
|
14
14
|
end
|
|
15
15
|
|
|
@@ -19,16 +19,16 @@ RSpec.describe Deimos::ActiveRecordConsume::BatchSlicer do
|
|
|
19
19
|
expect(slices).
|
|
20
20
|
to match([
|
|
21
21
|
match_array([
|
|
22
|
-
Deimos::Message.new({ v: 1 },
|
|
23
|
-
Deimos::Message.new({ v: 123 },
|
|
24
|
-
Deimos::Message.new({ v: 999 },
|
|
22
|
+
Deimos::Message.new({ v: 1 }, key: 'C'),
|
|
23
|
+
Deimos::Message.new({ v: 123 }, key: 'A'),
|
|
24
|
+
Deimos::Message.new({ v: 999 }, key: 'B')
|
|
25
25
|
]),
|
|
26
26
|
match_array([
|
|
27
|
-
Deimos::Message.new({ v: 456 },
|
|
28
|
-
Deimos::Message.new({ v: 2 },
|
|
27
|
+
Deimos::Message.new({ v: 456 }, key: 'A'),
|
|
28
|
+
Deimos::Message.new({ v: 2 }, key: 'C')
|
|
29
29
|
]),
|
|
30
30
|
match_array([
|
|
31
|
-
Deimos::Message.new({ v: 3 },
|
|
31
|
+
Deimos::Message.new({ v: 3 }, key: 'C')
|
|
32
32
|
])
|
|
33
33
|
])
|
|
34
34
|
end
|
|
@@ -33,25 +33,16 @@ module ActiveRecordConsumerTest
|
|
|
33
33
|
prepend_before(:each) do
|
|
34
34
|
|
|
35
35
|
consumer_class = Class.new(Deimos::ActiveRecordConsumer) do
|
|
36
|
-
schema 'MySchemaWithDateTimes'
|
|
37
|
-
namespace 'com.my-namespace'
|
|
38
|
-
key_config plain: true
|
|
39
36
|
record_class Widget
|
|
40
37
|
end
|
|
41
38
|
stub_const('MyConsumer', consumer_class)
|
|
42
39
|
|
|
43
40
|
consumer_class = Class.new(Deimos::ActiveRecordConsumer) do
|
|
44
|
-
schema 'MySchemaWithDateTimes'
|
|
45
|
-
namespace 'com.my-namespace'
|
|
46
|
-
key_config schema: 'MySchemaId_key'
|
|
47
41
|
record_class Widget
|
|
48
42
|
end
|
|
49
43
|
stub_const('MyConsumerWithKey', consumer_class)
|
|
50
44
|
|
|
51
45
|
consumer_class = Class.new(Deimos::ActiveRecordConsumer) do
|
|
52
|
-
schema 'MySchema'
|
|
53
|
-
namespace 'com.my-namespace'
|
|
54
|
-
key_config none: true
|
|
55
46
|
record_class Widget
|
|
56
47
|
|
|
57
48
|
# :nodoc:
|
|
@@ -135,14 +126,39 @@ module ActiveRecordConsumerTest
|
|
|
135
126
|
end
|
|
136
127
|
end
|
|
137
128
|
stub_const('Schemas::MySchemaWithDateTimes', schema_datetime_class)
|
|
129
|
+
|
|
130
|
+
Karafka::App.routes.redraw do
|
|
131
|
+
topic "my-topic" do
|
|
132
|
+
consumer MyConsumer
|
|
133
|
+
schema 'MySchemaWithDateTimes'
|
|
134
|
+
namespace 'com.my-namespace'
|
|
135
|
+
key_config plain: true
|
|
136
|
+
end
|
|
137
|
+
topic "my-topic2" do
|
|
138
|
+
consumer MyConsumerWithKey
|
|
139
|
+
schema 'MySchemaWithDateTimes'
|
|
140
|
+
namespace 'com.my-namespace'
|
|
141
|
+
key_config schema: 'MySchemaId_key'
|
|
142
|
+
end
|
|
143
|
+
topic "my-topic3" do
|
|
144
|
+
consumer MyCustomFetchConsumer
|
|
145
|
+
schema 'MySchema'
|
|
146
|
+
namespace 'com.my-namespace'
|
|
147
|
+
key_config none: true
|
|
148
|
+
end
|
|
149
|
+
end
|
|
138
150
|
end
|
|
139
151
|
|
|
140
152
|
describe 'consume' do
|
|
141
153
|
SCHEMA_CLASS_SETTINGS.each do |setting, use_schema_classes|
|
|
142
154
|
context "with Schema Class consumption #{setting}" do
|
|
143
155
|
before(:each) do
|
|
156
|
+
Karafka::App.routes.draw do
|
|
157
|
+
defaults do
|
|
158
|
+
use_schema_classes use_schema_classes
|
|
159
|
+
end
|
|
160
|
+
end
|
|
144
161
|
Deimos.configure do |config|
|
|
145
|
-
config.schema.use_schema_classes = use_schema_classes
|
|
146
162
|
config.schema.use_full_namespace = true
|
|
147
163
|
end
|
|
148
164
|
end
|
|
@@ -200,7 +216,7 @@ module ActiveRecordConsumerTest
|
|
|
200
216
|
test_consume_message(MyCustomFetchConsumer, {
|
|
201
217
|
test_id: 'id1',
|
|
202
218
|
some_int: 3
|
|
203
|
-
}
|
|
219
|
+
})
|
|
204
220
|
expect(widget1.reload.updated_at.in_time_zone).
|
|
205
221
|
to eq(Time.local(2020, 5, 6, 5, 5, 5))
|
|
206
222
|
travel_back
|
|
@@ -225,13 +241,13 @@ module ActiveRecordConsumerTest
|
|
|
225
241
|
test_consume_message(MyCustomFetchConsumer, {
|
|
226
242
|
test_id: 'id1',
|
|
227
243
|
some_int: 3
|
|
228
|
-
}
|
|
244
|
+
})
|
|
229
245
|
expect(widget1.reload.some_int).to eq(3)
|
|
230
246
|
expect(Widget.count).to eq(1)
|
|
231
247
|
test_consume_message(MyCustomFetchConsumer, {
|
|
232
248
|
test_id: 'id2',
|
|
233
249
|
some_int: 4
|
|
234
|
-
}
|
|
250
|
+
})
|
|
235
251
|
expect(Widget.count).to eq(2)
|
|
236
252
|
expect(Widget.find_by_test_id('id1').some_int).to eq(3)
|
|
237
253
|
expect(Widget.find_by_test_id('id2').some_int).to eq(4)
|
|
@@ -5,28 +5,13 @@ describe Deimos::ActiveRecordProducer do
|
|
|
5
5
|
include_context 'with widgets'
|
|
6
6
|
|
|
7
7
|
prepend_before(:each) do
|
|
8
|
-
|
|
9
|
-
producer_class = Class.new(Deimos::ActiveRecordProducer) do
|
|
10
|
-
schema 'MySchema'
|
|
11
|
-
namespace 'com.my-namespace'
|
|
12
|
-
topic 'my-topic'
|
|
13
|
-
key_config none: true
|
|
14
|
-
end
|
|
8
|
+
producer_class = Class.new(Deimos::ActiveRecordProducer)
|
|
15
9
|
stub_const('MyProducer', producer_class)
|
|
16
10
|
|
|
17
|
-
producer_class = Class.new(Deimos::ActiveRecordProducer)
|
|
18
|
-
schema 'MySchemaWithBooleans'
|
|
19
|
-
namespace 'com.my-namespace'
|
|
20
|
-
topic 'my-topic-with-boolean'
|
|
21
|
-
key_config none: true
|
|
22
|
-
end
|
|
11
|
+
producer_class = Class.new(Deimos::ActiveRecordProducer)
|
|
23
12
|
stub_const('MyBooleanProducer', producer_class)
|
|
24
13
|
|
|
25
14
|
producer_class = Class.new(Deimos::ActiveRecordProducer) do
|
|
26
|
-
schema 'MySchemaWithId'
|
|
27
|
-
namespace 'com.my-namespace'
|
|
28
|
-
topic 'my-topic-with-id'
|
|
29
|
-
key_config none: true
|
|
30
15
|
record_class Widget
|
|
31
16
|
|
|
32
17
|
# :nodoc:
|
|
@@ -38,19 +23,11 @@ describe Deimos::ActiveRecordProducer do
|
|
|
38
23
|
stub_const('MyProducerWithID', producer_class)
|
|
39
24
|
|
|
40
25
|
producer_class = Class.new(Deimos::ActiveRecordProducer) do
|
|
41
|
-
schema 'MySchemaWithUniqueId'
|
|
42
|
-
namespace 'com.my-namespace'
|
|
43
|
-
topic 'my-topic-with-unique-id'
|
|
44
|
-
key_config field: :id
|
|
45
26
|
record_class Widget
|
|
46
27
|
end
|
|
47
28
|
stub_const('MyProducerWithUniqueID', producer_class)
|
|
48
29
|
|
|
49
30
|
producer_class = Class.new(Deimos::ActiveRecordProducer) do
|
|
50
|
-
schema 'MySchemaWithUniqueId'
|
|
51
|
-
namespace 'com.my-namespace'
|
|
52
|
-
topic 'my-topic-with-unique-id'
|
|
53
|
-
key_config field: :id
|
|
54
31
|
record_class Widget
|
|
55
32
|
|
|
56
33
|
# :nodoc:
|
|
@@ -63,6 +40,39 @@ describe Deimos::ActiveRecordProducer do
|
|
|
63
40
|
end
|
|
64
41
|
|
|
65
42
|
stub_const('MyProducerWithPostProcess', producer_class)
|
|
43
|
+
Karafka::App.routes.redraw do
|
|
44
|
+
topic 'my-topic' do
|
|
45
|
+
schema 'MySchema'
|
|
46
|
+
namespace 'com.my-namespace'
|
|
47
|
+
key_config none: true
|
|
48
|
+
producer_class MyProducer
|
|
49
|
+
end
|
|
50
|
+
topic 'my-topic-with-boolean' do
|
|
51
|
+
producer_class MyBooleanProducer
|
|
52
|
+
schema 'MySchemaWithBooleans'
|
|
53
|
+
namespace 'com.my-namespace'
|
|
54
|
+
key_config none: true
|
|
55
|
+
end
|
|
56
|
+
topic 'my-topic-with-id' do
|
|
57
|
+
schema 'MySchemaWithId'
|
|
58
|
+
namespace 'com.my-namespace'
|
|
59
|
+
key_config none: true
|
|
60
|
+
producer_class MyProducerWithID
|
|
61
|
+
end
|
|
62
|
+
topic 'my-topic-with-unique-id' do
|
|
63
|
+
schema 'MySchemaWithUniqueId'
|
|
64
|
+
namespace 'com.my-namespace'
|
|
65
|
+
key_config field: :id
|
|
66
|
+
producer_class MyProducerWithUniqueID
|
|
67
|
+
end
|
|
68
|
+
topic 'my-topic-with-post-process' do
|
|
69
|
+
schema 'MySchemaWithUniqueId'
|
|
70
|
+
namespace 'com.my-namespace'
|
|
71
|
+
key_config none: true
|
|
72
|
+
producer_class MyProducerWithPostProcess
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
66
76
|
end
|
|
67
77
|
|
|
68
78
|
describe 'produce' do
|
|
@@ -117,7 +127,7 @@ describe Deimos::ActiveRecordProducer do
|
|
|
117
127
|
end
|
|
118
128
|
|
|
119
129
|
specify '#watched_attributes' do
|
|
120
|
-
expect(MyProducer.watched_attributes).to eq(%w(test_id some_int))
|
|
130
|
+
expect(MyProducer.watched_attributes(nil)).to eq(%w(test_id some_int))
|
|
121
131
|
end
|
|
122
132
|
|
|
123
133
|
end
|
data/spec/backends/base_spec.rb
CHANGED
|
@@ -8,27 +8,4 @@ RSpec.describe Deimos::Backends::Base do
|
|
|
8
8
|
described_class.publish(producer_class: MyProducer, messages: messages)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
describe 'payload_log method' do
|
|
12
|
-
it 'should return whole payload (default behavior)' do
|
|
13
|
-
log_message = described_class.send(:log_message, messages)
|
|
14
|
-
expect(log_message[:payloads].count).to eq(3)
|
|
15
|
-
expect(log_message[:payloads].first[:payload]).to eq({ 'foo' => 1 })
|
|
16
|
-
expect(log_message[:payloads].first[:key]).to eq('foo1')
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it 'should return only keys of messages' do
|
|
20
|
-
Deimos.config.payload_log = :keys
|
|
21
|
-
log_message = described_class.send(:log_message, messages)
|
|
22
|
-
expect(log_message[:payload_keys].count).to eq(3)
|
|
23
|
-
expect(log_message[:payload_keys]).to be_a(Array)
|
|
24
|
-
expect(log_message[:payload_keys].first).to eq('foo1')
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it 'should return only messages count' do
|
|
28
|
-
Deimos.config.payload_log = :count
|
|
29
|
-
log_message = described_class.send(:log_message, messages)
|
|
30
|
-
expect(log_message[:payloads_count]).to be_a(Integer)
|
|
31
|
-
expect(log_message[:payloads_count]).to eq(3)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
11
|
end
|
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
RSpec.describe Deimos::Backends::KafkaAsync do
|
|
4
4
|
include_context 'with publish_backend'
|
|
5
5
|
it 'should publish to Kafka asynchronously' do
|
|
6
|
-
producer
|
|
7
|
-
expect(producer).to receive(:async_publish_list).with(messages.map(&:encoded_hash))
|
|
8
|
-
expect(described_class).to receive(:producer).and_return(producer)
|
|
6
|
+
expect(Karafka.producer).to receive(:produce_many_async).with(messages)
|
|
9
7
|
described_class.publish(producer_class: MyProducer, messages: messages)
|
|
10
8
|
end
|
|
11
9
|
end
|
data/spec/backends/kafka_spec.rb
CHANGED
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
RSpec.describe Deimos::Backends::Kafka do
|
|
4
4
|
include_context 'with publish_backend'
|
|
5
5
|
it 'should publish to Kafka synchronously' do
|
|
6
|
-
producer
|
|
7
|
-
expect(producer).to receive(:publish_list).with(messages.map(&:encoded_hash))
|
|
8
|
-
expect(described_class).to receive(:producer).and_return(producer)
|
|
6
|
+
expect(Karafka.producer).to receive(:produce_many_sync).with(messages)
|
|
9
7
|
described_class.publish(producer_class: MyProducer, messages: messages)
|
|
10
8
|
end
|
|
11
9
|
end
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
each_db_config(Deimos::Backends::
|
|
3
|
+
each_db_config(Deimos::Backends::Outbox) do
|
|
4
4
|
include_context 'with publish_backend'
|
|
5
5
|
|
|
6
6
|
it 'should save to the database' do
|
|
7
|
-
expect(Deimos.config.metrics).to receive(:increment).with(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
)
|
|
7
|
+
# expect(Deimos.config.metrics).to receive(:increment).with(
|
|
8
|
+
# 'outbox.insert',
|
|
9
|
+
# tags: %w(topic:my-topic),
|
|
10
|
+
# by: 3
|
|
11
|
+
# )
|
|
12
12
|
described_class.publish(producer_class: MyProducer, messages: messages)
|
|
13
13
|
records = Deimos::KafkaMessage.all
|
|
14
14
|
expect(records.size).to eq(3)
|
|
15
15
|
expect(records[0].attributes.to_h).to include(
|
|
16
|
-
'message' => '{"
|
|
16
|
+
'message' => '{"test_id":"foo1","some_int":1}',
|
|
17
17
|
'topic' => 'my-topic',
|
|
18
|
-
'key' => 'foo1'
|
|
18
|
+
'key' => '{"test_id":"foo1"}'
|
|
19
19
|
)
|
|
20
20
|
expect(records[1].attributes.to_h).to include(
|
|
21
|
-
'message' => '{"
|
|
21
|
+
'message' => '{"test_id":"foo2","some_int":2}',
|
|
22
22
|
'topic' => 'my-topic',
|
|
23
|
-
'key' => 'foo2'
|
|
23
|
+
'key' => '{"test_id":"foo2"}'
|
|
24
24
|
)
|
|
25
25
|
expect(records[2].attributes.to_h).to include(
|
|
26
|
-
'message' => '{"
|
|
26
|
+
'message' => '{"test_id":"foo3","some_int":3}',
|
|
27
27
|
'topic' => 'my-topic',
|
|
28
|
-
'key' => 'foo3'
|
|
28
|
+
'key' => '{"test_id":"foo3"}'
|
|
29
29
|
)
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -37,18 +37,12 @@ each_db_config(Deimos::Backends::Db) do
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
it 'should add to non-keyed messages' do
|
|
40
|
+
orig_messages = messages.deep_dup
|
|
40
41
|
described_class.publish(producer_class: MyNoKeyProducer,
|
|
41
42
|
messages: messages)
|
|
42
43
|
expect(Deimos::KafkaMessage.count).to eq(3)
|
|
43
44
|
described_class.publish(producer_class: MyNoKeyProducer,
|
|
44
|
-
messages: [
|
|
45
|
+
messages: [orig_messages.first])
|
|
45
46
|
expect(Deimos::KafkaMessage.count).to eq(4)
|
|
46
47
|
end
|
|
47
|
-
|
|
48
|
-
it 'should add messages with Hash keys with JSON encoding' do
|
|
49
|
-
described_class.publish(producer_class: MyProducer,
|
|
50
|
-
messages: [build_message({ foo: 0 }, 'my-topic', { 'test_id' => 0 })])
|
|
51
|
-
expect(Deimos::KafkaMessage.count).to eq(1)
|
|
52
|
-
expect(Deimos::KafkaMessage.last.partition_key).to eq(%(---\ntest_id: 0\n))
|
|
53
|
-
end
|
|
54
48
|
end
|
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
|