deimos-kafka 1.0.0.pre.beta15
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 +7 -0
- data/.circleci/config.yml +74 -0
- data/.gitignore +41 -0
- data/.gitmodules +0 -0
- data/.rspec +1 -0
- data/.rubocop.yml +321 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +9 -0
- data/CODE_OF_CONDUCT.md +77 -0
- data/Dockerfile +23 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +165 -0
- data/Guardfile +22 -0
- data/LICENSE.md +195 -0
- data/README.md +742 -0
- data/Rakefile +13 -0
- data/bin/deimos +4 -0
- data/deimos-kafka.gemspec +42 -0
- data/docker-compose.yml +71 -0
- data/docs/DATABASE_BACKEND.md +147 -0
- data/docs/PULL_REQUEST_TEMPLATE.md +34 -0
- data/lib/deimos.rb +134 -0
- data/lib/deimos/active_record_consumer.rb +81 -0
- data/lib/deimos/active_record_producer.rb +64 -0
- data/lib/deimos/avro_data_coder.rb +89 -0
- data/lib/deimos/avro_data_decoder.rb +36 -0
- data/lib/deimos/avro_data_encoder.rb +51 -0
- data/lib/deimos/backends/db.rb +27 -0
- data/lib/deimos/backends/kafka.rb +27 -0
- data/lib/deimos/backends/kafka_async.rb +27 -0
- data/lib/deimos/configuration.rb +88 -0
- data/lib/deimos/consumer.rb +164 -0
- data/lib/deimos/instrumentation.rb +71 -0
- data/lib/deimos/kafka_message.rb +27 -0
- data/lib/deimos/kafka_source.rb +126 -0
- data/lib/deimos/kafka_topic_info.rb +79 -0
- data/lib/deimos/message.rb +74 -0
- data/lib/deimos/metrics/datadog.rb +47 -0
- data/lib/deimos/metrics/mock.rb +39 -0
- data/lib/deimos/metrics/provider.rb +38 -0
- data/lib/deimos/monkey_patches/phobos_cli.rb +35 -0
- data/lib/deimos/monkey_patches/phobos_producer.rb +51 -0
- data/lib/deimos/monkey_patches/ruby_kafka_heartbeat.rb +85 -0
- data/lib/deimos/monkey_patches/schema_store.rb +19 -0
- data/lib/deimos/producer.rb +218 -0
- data/lib/deimos/publish_backend.rb +30 -0
- data/lib/deimos/railtie.rb +8 -0
- data/lib/deimos/schema_coercer.rb +108 -0
- data/lib/deimos/shared_config.rb +59 -0
- data/lib/deimos/test_helpers.rb +356 -0
- data/lib/deimos/tracing/datadog.rb +35 -0
- data/lib/deimos/tracing/mock.rb +40 -0
- data/lib/deimos/tracing/provider.rb +31 -0
- data/lib/deimos/utils/db_producer.rb +95 -0
- data/lib/deimos/utils/executor.rb +117 -0
- data/lib/deimos/utils/inline_consumer.rb +144 -0
- data/lib/deimos/utils/lag_reporter.rb +182 -0
- data/lib/deimos/utils/platform_schema_validation.rb +0 -0
- data/lib/deimos/utils/signal_handler.rb +68 -0
- data/lib/deimos/version.rb +5 -0
- data/lib/generators/deimos/db_backend/templates/migration +24 -0
- data/lib/generators/deimos/db_backend/templates/rails3_migration +30 -0
- data/lib/generators/deimos/db_backend_generator.rb +48 -0
- data/lib/tasks/deimos.rake +17 -0
- data/spec/active_record_consumer_spec.rb +81 -0
- data/spec/active_record_producer_spec.rb +107 -0
- data/spec/avro_data_decoder_spec.rb +18 -0
- data/spec/avro_data_encoder_spec.rb +37 -0
- data/spec/backends/db_spec.rb +35 -0
- data/spec/backends/kafka_async_spec.rb +11 -0
- data/spec/backends/kafka_spec.rb +11 -0
- data/spec/consumer_spec.rb +169 -0
- data/spec/deimos_spec.rb +117 -0
- data/spec/kafka_source_spec.rb +168 -0
- data/spec/kafka_topic_info_spec.rb +88 -0
- data/spec/phobos.bad_db.yml +73 -0
- data/spec/phobos.yml +73 -0
- data/spec/producer_spec.rb +397 -0
- data/spec/publish_backend_spec.rb +10 -0
- data/spec/schemas/com/my-namespace/MySchema-key.avsc +13 -0
- data/spec/schemas/com/my-namespace/MySchema.avsc +18 -0
- data/spec/schemas/com/my-namespace/MySchemaWithBooleans.avsc +18 -0
- data/spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc +33 -0
- data/spec/schemas/com/my-namespace/MySchemaWithId.avsc +28 -0
- data/spec/schemas/com/my-namespace/MySchemaWithUniqueId.avsc +32 -0
- data/spec/schemas/com/my-namespace/Widget.avsc +27 -0
- data/spec/schemas/com/my-namespace/WidgetTheSecond.avsc +27 -0
- data/spec/spec_helper.rb +207 -0
- data/spec/updateable_schema_store_spec.rb +36 -0
- data/spec/utils/db_producer_spec.rb +208 -0
- data/spec/utils/executor_spec.rb +42 -0
- data/spec/utils/lag_reporter_spec.rb +69 -0
- data/spec/utils/platform_schema_validation_spec.rb +0 -0
- data/spec/utils/signal_handler_spec.rb +16 -0
- data/support/deimos-solo.png +0 -0
- data/support/deimos-with-name-next.png +0 -0
- data/support/deimos-with-name.png +0 -0
- data/support/flipp-logo.png +0 -0
- metadata +452 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'deimos/consumer'
|
4
|
+
|
5
|
+
module Deimos
|
6
|
+
# Consumer that automatically saves the payload into the database.
|
7
|
+
class ActiveRecordConsumer < Consumer
|
8
|
+
class << self
|
9
|
+
# param klass [Class < ActiveRecord::Base] the class used to save to the
|
10
|
+
# database.
|
11
|
+
def record_class(klass)
|
12
|
+
config[:record_class] = klass
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# :nodoc:
|
17
|
+
def consume(payload, metadata)
|
18
|
+
key = metadata.with_indifferent_access[:key]
|
19
|
+
klass = self.class.config[:record_class]
|
20
|
+
record = klass.where(klass.primary_key => key).first
|
21
|
+
if payload.nil?
|
22
|
+
destroy_record(record)
|
23
|
+
return
|
24
|
+
end
|
25
|
+
record ||= klass.new
|
26
|
+
attrs = record_attributes(payload.with_indifferent_access)
|
27
|
+
# don't use attributes= - bypass Rails < 5 attr_protected
|
28
|
+
attrs.each do |k, v|
|
29
|
+
record.send("#{k}=", v)
|
30
|
+
end
|
31
|
+
record[klass.primary_key] = key
|
32
|
+
record.created_at ||= Time.zone.now if record.respond_to?(:created_at)
|
33
|
+
record.updated_at ||= Time.zone.now if record.respond_to?(:updated_at)
|
34
|
+
record.save!
|
35
|
+
end
|
36
|
+
|
37
|
+
# Destroy a record that received a null payload. Override if you need
|
38
|
+
# to do something other than a straight destroy (e.g. mark as archived).
|
39
|
+
# @param record [ActiveRecord::Base]
|
40
|
+
def destroy_record(record)
|
41
|
+
record&.destroy
|
42
|
+
end
|
43
|
+
|
44
|
+
# Override this method (with `super`) if you want to add/change the default
|
45
|
+
# attributes set to the new/existing record.
|
46
|
+
# @param payload [Hash]
|
47
|
+
def record_attributes(payload)
|
48
|
+
klass = self.class.config[:record_class]
|
49
|
+
attributes = {}
|
50
|
+
schema = self.class.decoder.avro_schema
|
51
|
+
schema.fields.each do |field|
|
52
|
+
column = klass.columns.find { |c| c.name == field.name }
|
53
|
+
next if column.nil?
|
54
|
+
next if %w(updated_at created_at).include?(field.name)
|
55
|
+
|
56
|
+
attributes[field.name] = _coerce_field(field, column, payload[field.name])
|
57
|
+
end
|
58
|
+
attributes
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# @param field [Avro::Schema]
|
64
|
+
# @param column [ActiveRecord::ConnectionAdapters::Column]
|
65
|
+
# @param val [Object]
|
66
|
+
def _coerce_field(field, column, val)
|
67
|
+
return nil if val.nil?
|
68
|
+
|
69
|
+
field_type = field.type.type.to_sym
|
70
|
+
if field_type == :union
|
71
|
+
union_types = field.type.schemas.map { |s| s.type.to_sym }
|
72
|
+
field_type = union_types.find { |t| t != :null }
|
73
|
+
end
|
74
|
+
if column.type == :datetime && %i(int long).include?(field_type)
|
75
|
+
return Time.zone.strptime(val.to_s, '%s')
|
76
|
+
end
|
77
|
+
|
78
|
+
val
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'deimos/producer'
|
4
|
+
|
5
|
+
module Deimos
|
6
|
+
# Class which automatically produces a record when given an ActiveRecord
|
7
|
+
# instance or a list of them. Just call `send_events` on a list of records
|
8
|
+
# and they will be auto-published. You can override `generate_payload`
|
9
|
+
# to make changes to the payload before it's published.
|
10
|
+
#
|
11
|
+
# You can also call this with a list of hashes representing attributes.
|
12
|
+
# This is common when using activerecord-import.
|
13
|
+
class ActiveRecordProducer < Producer
|
14
|
+
class << self
|
15
|
+
# Indicate the class this producer is working on.
|
16
|
+
# @param klass [Class]
|
17
|
+
# @param refetch [Boolean] if true, and we are given a hash instead of
|
18
|
+
# a record object, refetch the record to pass into the `generate_payload`
|
19
|
+
# method.
|
20
|
+
def record_class(klass, refetch: true)
|
21
|
+
config[:record_class] = klass
|
22
|
+
config[:refetch_record] = refetch
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param record [ActiveRecord::Base]
|
26
|
+
# @param force_send [Boolean]
|
27
|
+
def send_event(record, force_send: false)
|
28
|
+
send_events([record], force_send: force_send)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param records [Array<ActiveRecord::Base>]
|
32
|
+
# @param force_send [Boolean]
|
33
|
+
def send_events(records, force_send: false)
|
34
|
+
primary_key = config[:record_class]&.primary_key
|
35
|
+
messages = records.map do |record|
|
36
|
+
if record.respond_to?(:attributes)
|
37
|
+
attrs = record.attributes.with_indifferent_access
|
38
|
+
else
|
39
|
+
attrs = record.with_indifferent_access
|
40
|
+
if config[:refetch_record] && attrs[primary_key]
|
41
|
+
record = config[:record_class].find(attrs[primary_key])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
generate_payload(attrs, record).with_indifferent_access
|
45
|
+
end
|
46
|
+
self.publish_list(messages, force_send: force_send)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Generate the payload, given a list of attributes or a record..
|
50
|
+
# Can be overridden or added to by subclasses.
|
51
|
+
# @param attributes [Hash]
|
52
|
+
# @param _record [ActiveRecord::Base] May be nil if refetch_record
|
53
|
+
# is not set.
|
54
|
+
# @return [Hash]
|
55
|
+
def generate_payload(attributes, _record)
|
56
|
+
schema = self.encoder.avro_schema
|
57
|
+
payload = attributes.stringify_keys
|
58
|
+
payload.delete_if do |k, _|
|
59
|
+
k.to_sym != :payload_key && !schema.fields.find { |f| f.name == k }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,89 @@
|
|
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
|
@@ -0,0 +1,36 @@
|
|
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
|
@@ -0,0 +1,51 @@
|
|
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
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'deimos/kafka_message'
|
4
|
+
|
5
|
+
module Deimos
|
6
|
+
module Backends
|
7
|
+
# Backend which saves messages to the database instead of immediately
|
8
|
+
# sending them.
|
9
|
+
class Db < Deimos::PublishBackend
|
10
|
+
class << self
|
11
|
+
# :nodoc:
|
12
|
+
def execute(producer_class:, messages:)
|
13
|
+
records = messages.map do |m|
|
14
|
+
message = Deimos::KafkaMessage.new(
|
15
|
+
message: m.encoded_payload.to_s.b,
|
16
|
+
topic: m.topic,
|
17
|
+
partition_key: m.partition_key || m.key
|
18
|
+
)
|
19
|
+
message.key = m.encoded_key.to_s.b unless producer_class.config[:no_keys]
|
20
|
+
message
|
21
|
+
end
|
22
|
+
Deimos::KafkaMessage.import(records)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deimos
|
4
|
+
module Backends
|
5
|
+
# Default backend to produce to Kafka.
|
6
|
+
class Kafka < Deimos::PublishBackend
|
7
|
+
include Phobos::Producer
|
8
|
+
|
9
|
+
# :nodoc:
|
10
|
+
def self.execute(producer_class:, messages:)
|
11
|
+
Deimos.instrument(
|
12
|
+
'produce',
|
13
|
+
producer: producer_class,
|
14
|
+
topic: producer_class.topic,
|
15
|
+
payloads: messages.map(&:payload)
|
16
|
+
) do
|
17
|
+
producer.publish_list(messages.map(&:encoded_hash))
|
18
|
+
Deimos.config.metrics&.increment(
|
19
|
+
'publish',
|
20
|
+
tags: %W(status:success topic:#{producer_class.topic}),
|
21
|
+
by: messages.size
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deimos
|
4
|
+
module Backends
|
5
|
+
# Backend which produces to Kafka via an async producer.
|
6
|
+
class KafkaAsync < Deimos::PublishBackend
|
7
|
+
include Phobos::Producer
|
8
|
+
|
9
|
+
# :nodoc:
|
10
|
+
def self.execute(producer_class:, messages:)
|
11
|
+
Deimos.instrument(
|
12
|
+
'produce',
|
13
|
+
producer: producer_class,
|
14
|
+
topic: producer_class.topic,
|
15
|
+
payloads: messages.map(&:payload)
|
16
|
+
) do
|
17
|
+
producer.async_publish_list(messages.map(&:encoded_hash))
|
18
|
+
Deimos.config.metrics&.increment(
|
19
|
+
'publish',
|
20
|
+
tags: %W(status:success topic:#{producer_class.topic}),
|
21
|
+
by: messages.size
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deimos
|
4
|
+
# Class to hold configuration.
|
5
|
+
class Configuration
|
6
|
+
# @return [Logger]
|
7
|
+
attr_accessor :logger
|
8
|
+
attr_accessor :phobos_logger
|
9
|
+
attr_accessor :kafka_logger
|
10
|
+
|
11
|
+
# By default, consumer errors will be consumed and logged to
|
12
|
+
# the metrics provider.
|
13
|
+
# Set this to true to force the error to be raised.
|
14
|
+
# @return [Boolean]
|
15
|
+
attr_accessor :reraise_consumer_errors
|
16
|
+
|
17
|
+
# @return [String]
|
18
|
+
attr_accessor :schema_registry_url
|
19
|
+
|
20
|
+
# @return [String]
|
21
|
+
attr_accessor :seed_broker
|
22
|
+
|
23
|
+
# Local path to schemas.
|
24
|
+
# @return [String]
|
25
|
+
attr_accessor :schema_path
|
26
|
+
|
27
|
+
# Default namespace for all producers. Can remain nil. Individual
|
28
|
+
# producers can override.
|
29
|
+
# @return [String]
|
30
|
+
attr_accessor :producer_schema_namespace
|
31
|
+
|
32
|
+
# Add a prefix to all topic names. This can be useful if you're using
|
33
|
+
# the same Kafka broker for different environments that are producing
|
34
|
+
# the same topics.
|
35
|
+
# @return [String]
|
36
|
+
attr_accessor :producer_topic_prefix
|
37
|
+
|
38
|
+
# Disable all actual message producing. Useful when doing things like
|
39
|
+
# mass imports or data space management when events don't need to be
|
40
|
+
# fired.
|
41
|
+
# @return [Boolean]
|
42
|
+
attr_accessor :disable_producers
|
43
|
+
|
44
|
+
# File path to the Phobos configuration file, relative to the application root.
|
45
|
+
# @return [String]
|
46
|
+
attr_accessor :phobos_config_file
|
47
|
+
|
48
|
+
# @return [Boolean]
|
49
|
+
attr_accessor :ssl_enabled
|
50
|
+
|
51
|
+
# @return [String]
|
52
|
+
attr_accessor :ssl_ca_cert
|
53
|
+
|
54
|
+
# @return [String]
|
55
|
+
attr_accessor :ssl_client_cert
|
56
|
+
|
57
|
+
# @return [String]
|
58
|
+
attr_accessor :ssl_client_cert_key
|
59
|
+
|
60
|
+
# Currently can be set to :db, :kafka, or :async_kafka. If using Kafka
|
61
|
+
# directly, set to async in your user-facing app, and sync in your
|
62
|
+
# consumers or delayed workers.
|
63
|
+
# @return [Symbol]
|
64
|
+
attr_accessor :publish_backend
|
65
|
+
|
66
|
+
# @return [Boolean]
|
67
|
+
attr_accessor :report_lag
|
68
|
+
|
69
|
+
# @return [Metrics::Provider]
|
70
|
+
attr_accessor :metrics
|
71
|
+
|
72
|
+
# @return [Tracing::Provider]
|
73
|
+
attr_accessor :tracer
|
74
|
+
|
75
|
+
# :nodoc:
|
76
|
+
def initialize
|
77
|
+
@phobos_config_file = 'config/phobos.yml'
|
78
|
+
@publish_backend = :kafka_async
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param other_config [Configuration]
|
82
|
+
# @return [Boolean]
|
83
|
+
def phobos_config_changed?(other_config)
|
84
|
+
phobos_keys = %w(phobos_config_file ssl_ca_cert ssl_client_cert ssl_client_cert_key)
|
85
|
+
phobos_keys.any? { |key| self.send(key) != other_config.send(key) }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|