deimos-ruby 1.8.1.pre.beta2 → 1.8.1.pre.beta3
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 +8 -0
- data/Gemfile.lock +1 -1
- data/lib/deimos/instrumentation.rb +10 -5
- data/lib/deimos/schema_backends/avro_schema_coercer.rb +30 -11
- data/lib/deimos/version.rb +1 -1
- data/spec/kafka_listener_spec.rb +54 -0
- data/spec/producer_spec.rb +34 -0
- data/spec/schemas/com/my-namespace/MyNestedSchema.avsc +55 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 380e0a86786dc4b308858186e5f97a102d13e0d0ac72ca172e941d42b6dfb81a
|
4
|
+
data.tar.gz: ca99315cf3ee096160c24f15d194ce73d77d95b1e7c27b3454e2a5e4165ef156
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8aa602000e702a9ce3c271b0796f4ea864fdc0acaf0852fdf7bdc3bf51e0eaf2df3265420e2558f37e3c174a5a555d43920323bb3a1539753b8821ae00ad6f32
|
7
|
+
data.tar.gz: c505ef8b587d2a405f9773a3c0f5a178f27811a071a4579ecfbe46c9f75759f1375b773949a384cdd465638ca7e95c53e6e34d8a1b7dd27e5128e03a90c0c3b1
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## UNRELEASED
|
9
9
|
|
10
|
+
## 1.8.1-beta3 - 2020-08-05
|
11
|
+
|
12
|
+
### Fixes :wrench:
|
13
|
+
- Simplify decoding messages and handle producer not found
|
14
|
+
- Consolidate types in sub-records recursively
|
15
|
+
(fixes [#72](https://github.com/flipp-oss/deimos/issues/72))
|
16
|
+
|
10
17
|
## 1.8.1-beta2 - 2020-07-28
|
11
18
|
|
12
19
|
### Features :star:
|
@@ -41,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
41
48
|
- Added `ActiveRecordConsumer` batch mode
|
42
49
|
|
43
50
|
### Fixes :wrench:
|
51
|
+
- Fixes `send_produce_error` to decode `failed_messages` with built-in decoder.
|
44
52
|
- Lag calculation can be incorrect if no messages are being consumed.
|
45
53
|
- Fixed bug where printing messages on a MessageSizeTooLarge
|
46
54
|
error didn't work.
|
data/Gemfile.lock
CHANGED
@@ -46,13 +46,18 @@ module Deimos
|
|
46
46
|
|
47
47
|
messages = exception.failed_messages
|
48
48
|
messages.group_by(&:topic).each do |topic, batch|
|
49
|
-
|
49
|
+
producer = Deimos::Producer.descendants.find { |c| c.topic == topic }
|
50
|
+
next if batch.empty? || !producer
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
decoder = Deimos.schema_backend(schema: producer.config[:schema],
|
53
|
+
namespace: producer.config[:namespace])
|
54
|
+
payloads = batch.map { |m| decoder.decode(m.value) }
|
53
55
|
|
54
|
-
Deimos.config.metrics&.
|
55
|
-
|
56
|
+
Deimos.config.metrics&.increment(
|
57
|
+
'publish_error',
|
58
|
+
tags: %W(topic:#{topic}),
|
59
|
+
by: payloads.size
|
60
|
+
)
|
56
61
|
Deimos.instrument(
|
57
62
|
'produce_error',
|
58
63
|
producer: producer,
|
@@ -10,18 +10,37 @@ module Deimos
|
|
10
10
|
@schema = schema
|
11
11
|
end
|
12
12
|
|
13
|
-
#
|
13
|
+
# Coerce sub-records in a payload to match the schema.
|
14
|
+
# @param type [Avro::Schema::UnionSchema]
|
15
|
+
# @param val [Object]
|
16
|
+
# @return [Object]
|
17
|
+
def coerce_union(type, val)
|
18
|
+
union_types = type.schemas.map { |s| s.type.to_sym }
|
19
|
+
return nil if val.nil? && union_types.include?(:null)
|
20
|
+
|
21
|
+
schema_type = type.schemas.find { |s| s.type.to_sym != :null }
|
22
|
+
coerce_type(schema_type, val)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Coerce sub-records in a payload to match the schema.
|
26
|
+
# @param type [Avro::Schema::RecordSchema]
|
27
|
+
# @param val [Object]
|
28
|
+
# @return [Object]
|
29
|
+
def coerce_record(type, val)
|
30
|
+
record = val.map do |name, value|
|
31
|
+
field = type.fields.find { |f| f.name == name }
|
32
|
+
coerce_type(field.type, value)
|
33
|
+
end
|
34
|
+
val.keys.zip(record).to_h
|
35
|
+
end
|
36
|
+
|
37
|
+
# Coerce values in a payload to match the schema.
|
38
|
+
# @param type [Avro::Schema]
|
14
39
|
# @param val [Object]
|
15
40
|
# @return [Object]
|
16
41
|
def coerce_type(type, val)
|
17
42
|
int_classes = [Time, ActiveSupport::TimeWithZone]
|
18
43
|
field_type = type.type.to_sym
|
19
|
-
if field_type == :union
|
20
|
-
union_types = type.schemas.map { |s| s.type.to_sym }
|
21
|
-
return nil if val.nil? && union_types.include?(:null)
|
22
|
-
|
23
|
-
field_type = union_types.find { |t| t != :null }
|
24
|
-
end
|
25
44
|
|
26
45
|
case field_type
|
27
46
|
when :int, :long
|
@@ -32,14 +51,12 @@ module Deimos
|
|
32
51
|
else
|
33
52
|
val # this will fail
|
34
53
|
end
|
35
|
-
|
36
54
|
when :float, :double
|
37
55
|
if val.is_a?(Numeric) || _is_float_string?(val)
|
38
56
|
val.to_f
|
39
57
|
else
|
40
58
|
val # this will fail
|
41
59
|
end
|
42
|
-
|
43
60
|
when :string
|
44
61
|
if val.respond_to?(:to_str)
|
45
62
|
val.to_s
|
@@ -54,8 +71,10 @@ module Deimos
|
|
54
71
|
else
|
55
72
|
true
|
56
73
|
end
|
57
|
-
|
58
|
-
val
|
74
|
+
when :union
|
75
|
+
coerce_union(type, val)
|
76
|
+
when :record
|
77
|
+
coerce_record(type, val)
|
59
78
|
end
|
60
79
|
end
|
61
80
|
|
data/lib/deimos/version.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Deimos::KafkaListener do
|
4
|
+
include_context 'with widgets'
|
5
|
+
|
6
|
+
prepend_before(:each) do
|
7
|
+
producer_class = Class.new(Deimos::Producer) do
|
8
|
+
schema 'MySchema'
|
9
|
+
namespace 'com.my-namespace'
|
10
|
+
topic 'my-topic'
|
11
|
+
key_config none: true
|
12
|
+
end
|
13
|
+
stub_const('MyProducer', producer_class)
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
Deimos.configure do |c|
|
18
|
+
c.producers.backend = :kafka
|
19
|
+
c.schema.backend = :avro_local
|
20
|
+
end
|
21
|
+
allow_any_instance_of(Kafka::Cluster).to receive(:add_target_topics)
|
22
|
+
allow_any_instance_of(Kafka::Cluster).to receive(:partitions_for).
|
23
|
+
and_raise(Kafka::Error)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '.send_produce_error' do
|
27
|
+
let(:payloads) do
|
28
|
+
[{ 'test_id' => 'foo', 'some_int' => 123 },
|
29
|
+
{ 'test_id' => 'bar', 'some_int' => 124 }]
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should listen to publishing errors and republish as Deimos events' do
|
33
|
+
Deimos.subscribe('produce_error') do |event|
|
34
|
+
expect(event.payload).to include(
|
35
|
+
producer: MyProducer,
|
36
|
+
topic: 'my-topic',
|
37
|
+
payloads: payloads
|
38
|
+
)
|
39
|
+
end
|
40
|
+
expect(Deimos.config.metrics).to receive(:increment).
|
41
|
+
with('publish_error', tags: %w(topic:my-topic), by: 2)
|
42
|
+
expect { MyProducer.publish_list(payloads) }.to raise_error(Kafka::DeliveryFailed)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should not send any notifications when producer is not found' do
|
46
|
+
Deimos.subscribe('produce_error') do |_|
|
47
|
+
raise 'OH NOES'
|
48
|
+
end
|
49
|
+
allow(Deimos::Producer).to receive(:descendants).and_return([])
|
50
|
+
expect(Deimos.config.metrics).not_to receive(:increment).with('publish_error', anything)
|
51
|
+
expect { MyProducer.publish_list(payloads) }.to raise_error(Kafka::DeliveryFailed)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/producer_spec.rb
CHANGED
@@ -41,6 +41,14 @@ module ProducerTest
|
|
41
41
|
end
|
42
42
|
stub_const('MyNoKeyProducer', producer_class)
|
43
43
|
|
44
|
+
producer_class = Class.new(Deimos::Producer) do
|
45
|
+
schema 'MyNestedSchema'
|
46
|
+
namespace 'com.my-namespace'
|
47
|
+
topic 'my-topic'
|
48
|
+
key_config field: 'test_id'
|
49
|
+
end
|
50
|
+
stub_const('MyNestedSchemaProducer', producer_class)
|
51
|
+
|
44
52
|
producer_class = Class.new(Deimos::Producer) do
|
45
53
|
schema 'MySchema'
|
46
54
|
namespace 'com.my-namespace'
|
@@ -233,6 +241,32 @@ module ProducerTest
|
|
233
241
|
)
|
234
242
|
end
|
235
243
|
|
244
|
+
it 'should properly encode and coerce values with a nested record' do
|
245
|
+
expect(MyNestedSchemaProducer.encoder).to receive(:encode_key).with('test_id', 'foo', topic: 'my-topic-key')
|
246
|
+
MyNestedSchemaProducer.publish(
|
247
|
+
'test_id' => 'foo',
|
248
|
+
'test_float' => BigDecimal('123.456'),
|
249
|
+
'some_nested_record' => {
|
250
|
+
'some_int' => 123,
|
251
|
+
'some_float' => BigDecimal('456.789'),
|
252
|
+
'some_string' => '123',
|
253
|
+
'some_optional_int' => nil
|
254
|
+
},
|
255
|
+
'some_optional_record' => nil
|
256
|
+
)
|
257
|
+
expect(MyNestedSchemaProducer.topic).to have_sent(
|
258
|
+
'test_id' => 'foo',
|
259
|
+
'test_float' => 123.456,
|
260
|
+
'some_nested_record' => {
|
261
|
+
'some_int' => 123,
|
262
|
+
'some_float' => 456.789,
|
263
|
+
'some_string' => '123',
|
264
|
+
'some_optional_int' => nil
|
265
|
+
},
|
266
|
+
'some_optional_record' => nil
|
267
|
+
)
|
268
|
+
end
|
269
|
+
|
236
270
|
it 'should error with nothing set' do
|
237
271
|
expect {
|
238
272
|
MyErrorProducer.publish_list(
|
@@ -0,0 +1,55 @@
|
|
1
|
+
{
|
2
|
+
"namespace": "com.my-namespace",
|
3
|
+
"name": "MyNestedSchema",
|
4
|
+
"type": "record",
|
5
|
+
"doc": "Test schema",
|
6
|
+
"fields": [
|
7
|
+
{
|
8
|
+
"name": "test_id",
|
9
|
+
"type": "string",
|
10
|
+
"doc": "test string"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"name": "test_float",
|
14
|
+
"type": "float",
|
15
|
+
"doc": "test float"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"name": "some_nested_record",
|
19
|
+
"doc": "some nested record",
|
20
|
+
"type": {
|
21
|
+
"name": "MyNestedRecord",
|
22
|
+
"type": "record",
|
23
|
+
"fields": [
|
24
|
+
{
|
25
|
+
"name": "some_int",
|
26
|
+
"type": "int",
|
27
|
+
"doc": "some int"
|
28
|
+
},
|
29
|
+
{
|
30
|
+
"name": "some_float",
|
31
|
+
"type": "float",
|
32
|
+
"doc": "some float"
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"name": "some_string",
|
36
|
+
"type": "string",
|
37
|
+
"doc": "some string"
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"name": "some_optional_int",
|
41
|
+
"type": [ "null", "int" ],
|
42
|
+
"doc": "some optional int",
|
43
|
+
"default": null
|
44
|
+
}
|
45
|
+
]
|
46
|
+
}
|
47
|
+
},
|
48
|
+
{
|
49
|
+
"name": "some_optional_record",
|
50
|
+
"doc": "some optional record",
|
51
|
+
"type": [ "null", "MyNestedRecord" ],
|
52
|
+
"default": null
|
53
|
+
}
|
54
|
+
]
|
55
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deimos-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.1.pre.
|
4
|
+
version: 1.8.1.pre.beta3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Orner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro_turf
|
@@ -428,6 +428,7 @@ files:
|
|
428
428
|
- spec/generators/active_record_generator_spec.rb
|
429
429
|
- spec/handlers/my_batch_consumer.rb
|
430
430
|
- spec/handlers/my_consumer.rb
|
431
|
+
- spec/kafka_listener_spec.rb
|
431
432
|
- spec/kafka_source_spec.rb
|
432
433
|
- spec/kafka_topic_info_spec.rb
|
433
434
|
- spec/message_spec.rb
|
@@ -441,6 +442,7 @@ files:
|
|
441
442
|
- spec/schema_backends/avro_validation_spec.rb
|
442
443
|
- spec/schema_backends/base_spec.rb
|
443
444
|
- spec/schemas/com/my-namespace/Generated.avsc
|
445
|
+
- spec/schemas/com/my-namespace/MyNestedSchema.avsc
|
444
446
|
- spec/schemas/com/my-namespace/MySchema-key.avsc
|
445
447
|
- spec/schemas/com/my-namespace/MySchema.avsc
|
446
448
|
- spec/schemas/com/my-namespace/MySchemaCompound-key.avsc
|
@@ -507,6 +509,7 @@ test_files:
|
|
507
509
|
- spec/generators/active_record_generator_spec.rb
|
508
510
|
- spec/handlers/my_batch_consumer.rb
|
509
511
|
- spec/handlers/my_consumer.rb
|
512
|
+
- spec/kafka_listener_spec.rb
|
510
513
|
- spec/kafka_source_spec.rb
|
511
514
|
- spec/kafka_topic_info_spec.rb
|
512
515
|
- spec/message_spec.rb
|
@@ -520,6 +523,7 @@ test_files:
|
|
520
523
|
- spec/schema_backends/avro_validation_spec.rb
|
521
524
|
- spec/schema_backends/base_spec.rb
|
522
525
|
- spec/schemas/com/my-namespace/Generated.avsc
|
526
|
+
- spec/schemas/com/my-namespace/MyNestedSchema.avsc
|
523
527
|
- spec/schemas/com/my-namespace/MySchema-key.avsc
|
524
528
|
- spec/schemas/com/my-namespace/MySchema.avsc
|
525
529
|
- spec/schemas/com/my-namespace/MySchemaCompound-key.avsc
|