deimos-ruby 1.4.0.pre.beta7 → 1.5.0.pre.beta2
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 +3 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +140 -58
- data/README.md +38 -11
- data/Rakefile +2 -2
- data/deimos-ruby.gemspec +3 -2
- data/docs/CONFIGURATION.md +1 -0
- data/docs/DATABASE_BACKEND.md +1 -1
- data/lib/deimos/active_record_consumer.rb +11 -12
- data/lib/deimos/active_record_producer.rb +2 -2
- data/lib/deimos/backends/base.rb +32 -0
- data/lib/deimos/backends/db.rb +6 -1
- data/lib/deimos/backends/kafka.rb +1 -1
- data/lib/deimos/backends/kafka_async.rb +1 -1
- data/lib/deimos/backends/test.rb +20 -0
- data/lib/deimos/base_consumer.rb +7 -7
- data/lib/deimos/batch_consumer.rb +0 -1
- data/lib/deimos/config/configuration.rb +4 -0
- data/lib/deimos/consumer.rb +0 -2
- data/lib/deimos/kafka_source.rb +1 -1
- data/lib/deimos/kafka_topic_info.rb +1 -1
- data/lib/deimos/message.rb +7 -7
- data/lib/deimos/producer.rb +10 -12
- data/lib/deimos/schema_backends/avro_base.rb +108 -0
- data/lib/deimos/schema_backends/avro_local.rb +30 -0
- data/lib/deimos/{schema_coercer.rb → schema_backends/avro_schema_coercer.rb} +39 -51
- data/lib/deimos/schema_backends/avro_schema_registry.rb +34 -0
- data/lib/deimos/schema_backends/avro_validation.rb +21 -0
- data/lib/deimos/schema_backends/base.rb +130 -0
- data/lib/deimos/schema_backends/mock.rb +42 -0
- data/lib/deimos/test_helpers.rb +42 -168
- data/lib/deimos/utils/db_producer.rb +5 -0
- data/lib/deimos/version.rb +1 -1
- data/lib/deimos.rb +22 -6
- data/lib/tasks/deimos.rake +1 -1
- data/spec/active_record_consumer_spec.rb +7 -0
- data/spec/{publish_backend_spec.rb → backends/base_spec.rb} +1 -1
- data/spec/backends/db_spec.rb +5 -0
- data/spec/batch_consumer_spec.rb +0 -8
- data/spec/config/configuration_spec.rb +20 -20
- data/spec/consumer_spec.rb +0 -1
- data/spec/deimos_spec.rb +0 -4
- data/spec/kafka_source_spec.rb +8 -0
- data/spec/producer_spec.rb +23 -37
- data/spec/rake_spec.rb +19 -0
- data/spec/schema_backends/avro_base_shared.rb +174 -0
- data/spec/schema_backends/avro_local_spec.rb +32 -0
- data/spec/schema_backends/avro_schema_registry_spec.rb +32 -0
- data/spec/schema_backends/avro_validation_spec.rb +24 -0
- data/spec/schema_backends/base_spec.rb +29 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/utils/db_producer_spec.rb +10 -0
- metadata +56 -33
- data/lib/deimos/avro_data_coder.rb +0 -89
- data/lib/deimos/avro_data_decoder.rb +0 -36
- data/lib/deimos/avro_data_encoder.rb +0 -51
- data/lib/deimos/monkey_patches/schema_store.rb +0 -19
- data/lib/deimos/publish_backend.rb +0 -30
- data/spec/avro_data_decoder_spec.rb +0 -18
- data/spec/avro_data_encoder_spec.rb +0 -37
- data/spec/updateable_schema_store_spec.rb +0 -36
@@ -1,89 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Deimos
|
4
|
-
# Base class for the encoder / decoder classes.
|
5
|
-
class AvroDataCoder
|
6
|
-
attr_accessor :schema, :namespace, :config, :schema_store
|
7
|
-
|
8
|
-
# @param schema [String]
|
9
|
-
# @param namespace [String]
|
10
|
-
# @param schema_store [AvroTurf::SchemaStore]
|
11
|
-
def initialize(schema:, namespace:, schema_store: nil)
|
12
|
-
@schema = schema
|
13
|
-
@namespace = namespace
|
14
|
-
@schema_store = schema_store ||
|
15
|
-
AvroTurf::SchemaStore.new(path: Deimos.config.schema.path)
|
16
|
-
end
|
17
|
-
|
18
|
-
# @param schema [String]
|
19
|
-
# @return [Avro::Schema]
|
20
|
-
def avro_schema(schema=nil)
|
21
|
-
schema ||= @schema
|
22
|
-
@schema_store.find(schema, @namespace)
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
# @return [AvroTurf]
|
28
|
-
def avro_turf
|
29
|
-
@avro_turf ||= AvroTurf.new(
|
30
|
-
schemas_path: Deimos.config.schema.path,
|
31
|
-
schema_store: @schema_store
|
32
|
-
)
|
33
|
-
@avro_turf
|
34
|
-
end
|
35
|
-
|
36
|
-
# @return [AvroTurf::Messaging]
|
37
|
-
def avro_turf_messaging
|
38
|
-
@avro_turf_messaging ||= AvroTurf::Messaging.new(
|
39
|
-
schema_store: @schema_store,
|
40
|
-
registry_url: Deimos.config.schema.registry_url,
|
41
|
-
schemas_path: Deimos.config.schema.path,
|
42
|
-
namespace: @namespace
|
43
|
-
)
|
44
|
-
end
|
45
|
-
|
46
|
-
# Generate a key schema from the given value schema and key ID. This
|
47
|
-
# is used when encoding or decoding keys from an existing value schema.
|
48
|
-
# @param key_id [Symbol]
|
49
|
-
# @return [Hash]
|
50
|
-
def _generate_key_schema(key_id)
|
51
|
-
return @key_schema if @key_schema
|
52
|
-
|
53
|
-
value_schema = @schema_store.find(@schema, @namespace)
|
54
|
-
key_field = value_schema.fields.find { |f| f.name == key_id.to_s }
|
55
|
-
name = _key_schema_name(@schema)
|
56
|
-
@key_schema = {
|
57
|
-
'type' => 'record',
|
58
|
-
'name' => name,
|
59
|
-
'namespace' => @namespace,
|
60
|
-
'doc' => "Key for #{@namespace}.#{@schema}",
|
61
|
-
'fields' => [
|
62
|
-
{
|
63
|
-
'name' => key_id,
|
64
|
-
'type' => key_field.type.type_sym.to_s
|
65
|
-
}
|
66
|
-
]
|
67
|
-
}
|
68
|
-
@schema_store.add_schema(@key_schema)
|
69
|
-
@key_schema
|
70
|
-
end
|
71
|
-
|
72
|
-
# @param value_schema [Hash]
|
73
|
-
# @return [String]
|
74
|
-
def _field_name_from_schema(value_schema)
|
75
|
-
raise "Schema #{@schema} not found!" if value_schema.nil?
|
76
|
-
if value_schema['fields'].nil? || value_schema['fields'].empty?
|
77
|
-
raise "Schema #{@schema} has no fields!"
|
78
|
-
end
|
79
|
-
|
80
|
-
value_schema['fields'][0]['name']
|
81
|
-
end
|
82
|
-
|
83
|
-
# @param schema [String]
|
84
|
-
# @return [String]
|
85
|
-
def _key_schema_name(schema)
|
86
|
-
"#{schema.gsub('-value', '')}_key"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'avro_turf/messaging'
|
4
|
-
require 'deimos/avro_data_coder'
|
5
|
-
|
6
|
-
module Deimos
|
7
|
-
# Service Object to decode avro messages
|
8
|
-
class AvroDataDecoder < AvroDataCoder
|
9
|
-
# Decode some data.
|
10
|
-
# @param payload [Hash|String]
|
11
|
-
# @param schema [String]
|
12
|
-
# @return [Hash]
|
13
|
-
def decode(payload, schema: nil)
|
14
|
-
schema ||= @schema
|
15
|
-
avro_turf_messaging.decode(payload, schema_name: schema)
|
16
|
-
end
|
17
|
-
|
18
|
-
# Decode against a local schema.
|
19
|
-
# @param payload [Hash]
|
20
|
-
# @param schema [String]
|
21
|
-
# @return [Hash]
|
22
|
-
def decode_local(payload, schema: nil)
|
23
|
-
schema ||= @schema
|
24
|
-
avro_turf.decode(payload, schema_name: schema, namespace: @namespace)
|
25
|
-
end
|
26
|
-
|
27
|
-
# @param payload [String] the encoded key.
|
28
|
-
# @param key_id [String|Symbol]
|
29
|
-
# @return [Object] the decoded key (int/long/string).
|
30
|
-
def decode_key(payload, key_id)
|
31
|
-
key_schema = _generate_key_schema(key_id)
|
32
|
-
field_name = _field_name_from_schema(key_schema)
|
33
|
-
decode(payload, schema: key_schema['name'])[field_name]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'avro_turf/messaging'
|
4
|
-
require 'deimos/avro_data_coder'
|
5
|
-
|
6
|
-
module Deimos
|
7
|
-
# Service Object to decode Avro messages.
|
8
|
-
class AvroDataEncoder < AvroDataCoder
|
9
|
-
# @param payload [Hash]
|
10
|
-
# @param schema [String]
|
11
|
-
# @return [String]
|
12
|
-
def encode_local(payload, schema: nil)
|
13
|
-
schema ||= @schema
|
14
|
-
Avro::SchemaValidator.validate!(avro_schema(schema), payload,
|
15
|
-
recursive: true,
|
16
|
-
fail_on_extra_fields: true)
|
17
|
-
avro_turf.encode(payload, schema_name: schema, namespace: @namespace)
|
18
|
-
rescue Avro::IO::AvroTypeError
|
19
|
-
# throw a more detailed error
|
20
|
-
value_schema = @schema_store.find(schema, @namespace)
|
21
|
-
Avro::SchemaValidator.validate!(value_schema, payload)
|
22
|
-
end
|
23
|
-
|
24
|
-
# @param payload [Hash]
|
25
|
-
# @param schema [String]
|
26
|
-
# @param topic [String]
|
27
|
-
# @return [String]
|
28
|
-
def encode(payload, schema: nil, topic: nil)
|
29
|
-
schema ||= @schema
|
30
|
-
Avro::SchemaValidator.validate!(avro_schema(schema), payload,
|
31
|
-
recursive: true,
|
32
|
-
fail_on_extra_fields: true)
|
33
|
-
avro_turf_messaging.encode(payload, schema_name: schema, subject: topic)
|
34
|
-
rescue Avro::IO::AvroTypeError
|
35
|
-
# throw a more detailed error
|
36
|
-
schema = @schema_store.find(@schema, @namespace)
|
37
|
-
Avro::SchemaValidator.validate!(schema, payload)
|
38
|
-
end
|
39
|
-
|
40
|
-
# @param key_id [Symbol|String]
|
41
|
-
# @param key [Object]
|
42
|
-
# @param topic [String]
|
43
|
-
# @return [String] the encoded key.
|
44
|
-
def encode_key(key_id, key, topic=nil)
|
45
|
-
key_schema = _generate_key_schema(key_id)
|
46
|
-
field_name = _field_name_from_schema(key_schema)
|
47
|
-
payload = { field_name => key }
|
48
|
-
encode(payload, schema: key_schema['name'], topic: topic)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'avro_turf/schema_store'
|
4
|
-
|
5
|
-
# Allows us to add in-memory schemas to the schema store in
|
6
|
-
# addition to the ones stored in the file system.
|
7
|
-
class AvroTurf::SchemaStore
|
8
|
-
attr_accessor :schemas
|
9
|
-
|
10
|
-
# @param schema_hash [Hash]
|
11
|
-
def add_schema(schema_hash)
|
12
|
-
name = schema_hash['name']
|
13
|
-
namespace = schema_hash['namespace']
|
14
|
-
full_name = Avro::Name.make_fullname(name, namespace)
|
15
|
-
return if @schemas.key?(full_name)
|
16
|
-
|
17
|
-
Avro::Schema.real_parse(schema_hash, @schemas)
|
18
|
-
end
|
19
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Deimos
|
4
|
-
# Abstract class for all publish backends.
|
5
|
-
class PublishBackend
|
6
|
-
class << self
|
7
|
-
# @param producer_class [Class < Deimos::Producer]
|
8
|
-
# @param messages [Array<Deimos::Message>]
|
9
|
-
def publish(producer_class:, messages:)
|
10
|
-
Deimos.config.logger.info(
|
11
|
-
message: 'Publishing messages',
|
12
|
-
topic: producer_class.topic,
|
13
|
-
payloads: messages.map do |message|
|
14
|
-
{
|
15
|
-
payload: message.payload,
|
16
|
-
key: message.key
|
17
|
-
}
|
18
|
-
end
|
19
|
-
)
|
20
|
-
execute(producer_class: producer_class, messages: messages)
|
21
|
-
end
|
22
|
-
|
23
|
-
# @param producer_class [Class < Deimos::Producer]
|
24
|
-
# @param messages [Array<Deimos::Message>]
|
25
|
-
def execute(producer_class:, messages:)
|
26
|
-
raise NotImplementedError
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Deimos::AvroDataDecoder do
|
4
|
-
|
5
|
-
let(:decoder) do
|
6
|
-
decoder = described_class.new(schema: 'MySchema',
|
7
|
-
namespace: 'com.my-namespace')
|
8
|
-
allow(decoder).to(receive(:decode)) { |payload| payload }
|
9
|
-
decoder
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'should decode a key' do
|
13
|
-
# reset stub from TestHelpers
|
14
|
-
allow(described_class).to receive(:new).and_call_original
|
15
|
-
expect(decoder.decode_key({ 'test_id' => '123' }, 'test_id')).to eq('123')
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'avro_turf/messaging'
|
4
|
-
|
5
|
-
describe Deimos::AvroDataEncoder do
|
6
|
-
|
7
|
-
let(:encoder) do
|
8
|
-
encoder = described_class.new(schema: 'MySchema',
|
9
|
-
namespace: 'com.my-namespace')
|
10
|
-
allow(encoder).to(receive(:encode)) { |payload| payload }
|
11
|
-
encoder
|
12
|
-
end
|
13
|
-
|
14
|
-
specify 'generate_key_schema' do
|
15
|
-
expect_any_instance_of(AvroTurf::SchemaStore).
|
16
|
-
to receive(:add_schema).with(
|
17
|
-
'type' => 'record',
|
18
|
-
'name' => 'MySchema_key',
|
19
|
-
'namespace' => 'com.my-namespace',
|
20
|
-
'doc' => 'Key for com.my-namespace.MySchema',
|
21
|
-
'fields' => [
|
22
|
-
{
|
23
|
-
'name' => 'test_id',
|
24
|
-
'type' => 'string'
|
25
|
-
}
|
26
|
-
]
|
27
|
-
)
|
28
|
-
encoder.send(:_generate_key_schema, 'test_id')
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should encode a key' do
|
32
|
-
# reset stub from TestHelpers
|
33
|
-
allow(described_class).to receive(:new).and_call_original
|
34
|
-
expect(encoder.encode_key('test_id', '123')).to eq('test_id' => '123')
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe AvroTurf::SchemaStore do
|
4
|
-
|
5
|
-
it 'should add an in-memory schema' do
|
6
|
-
schema_store = described_class.new(path: Deimos.config.schema.path)
|
7
|
-
schema_store.load_schemas!
|
8
|
-
found_schema = schema_store.find('MySchema', 'com.my-namespace').as_json
|
9
|
-
expect(found_schema['name']).to eq('MySchema')
|
10
|
-
expect(found_schema['namespace']).to eq('com.my-namespace')
|
11
|
-
expect(found_schema['fields'].size).to eq(2)
|
12
|
-
expect(found_schema['fields'][0]['type']['type_sym']).to eq('string')
|
13
|
-
expect(found_schema['fields'][0]['name']).to eq('test_id')
|
14
|
-
new_schema = {
|
15
|
-
'namespace' => 'com.my-namespace',
|
16
|
-
'name' => 'MyNewSchema',
|
17
|
-
'type' => 'record',
|
18
|
-
'doc' => 'Test schema',
|
19
|
-
'fields' => [
|
20
|
-
{
|
21
|
-
'name' => 'my_id',
|
22
|
-
'type' => 'int',
|
23
|
-
'doc' => 'test int'
|
24
|
-
}
|
25
|
-
]
|
26
|
-
}
|
27
|
-
schema_store.add_schema(new_schema)
|
28
|
-
found_schema = schema_store.find('MyNewSchema', 'com.my-namespace').
|
29
|
-
as_json
|
30
|
-
expect(found_schema['name']).to eq('MyNewSchema')
|
31
|
-
expect(found_schema['namespace']).to eq('com.my-namespace')
|
32
|
-
expect(found_schema['fields'].size).to eq(1)
|
33
|
-
expect(found_schema['fields'][0]['type']['type_sym']).to eq('int')
|
34
|
-
expect(found_schema['fields'][0]['name']).to eq('my_id')
|
35
|
-
end
|
36
|
-
end
|