deimos-temp-fork 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +83 -0
  3. data/.gitignore +41 -0
  4. data/.gitmodules +0 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +333 -0
  7. data/.ruby-gemset +1 -0
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +349 -0
  10. data/CODE_OF_CONDUCT.md +77 -0
  11. data/Dockerfile +23 -0
  12. data/Gemfile +6 -0
  13. data/Gemfile.lock +286 -0
  14. data/Guardfile +22 -0
  15. data/LICENSE.md +195 -0
  16. data/README.md +1099 -0
  17. data/Rakefile +13 -0
  18. data/bin/deimos +4 -0
  19. data/deimos-ruby.gemspec +44 -0
  20. data/docker-compose.yml +71 -0
  21. data/docs/ARCHITECTURE.md +140 -0
  22. data/docs/CONFIGURATION.md +236 -0
  23. data/docs/DATABASE_BACKEND.md +147 -0
  24. data/docs/INTEGRATION_TESTS.md +52 -0
  25. data/docs/PULL_REQUEST_TEMPLATE.md +35 -0
  26. data/docs/UPGRADING.md +128 -0
  27. data/lib/deimos-temp-fork.rb +95 -0
  28. data/lib/deimos/active_record_consume/batch_consumption.rb +164 -0
  29. data/lib/deimos/active_record_consume/batch_slicer.rb +27 -0
  30. data/lib/deimos/active_record_consume/message_consumption.rb +79 -0
  31. data/lib/deimos/active_record_consume/schema_model_converter.rb +52 -0
  32. data/lib/deimos/active_record_consumer.rb +67 -0
  33. data/lib/deimos/active_record_producer.rb +87 -0
  34. data/lib/deimos/backends/base.rb +32 -0
  35. data/lib/deimos/backends/db.rb +41 -0
  36. data/lib/deimos/backends/kafka.rb +33 -0
  37. data/lib/deimos/backends/kafka_async.rb +33 -0
  38. data/lib/deimos/backends/test.rb +20 -0
  39. data/lib/deimos/batch_consumer.rb +7 -0
  40. data/lib/deimos/config/configuration.rb +381 -0
  41. data/lib/deimos/config/phobos_config.rb +137 -0
  42. data/lib/deimos/consume/batch_consumption.rb +150 -0
  43. data/lib/deimos/consume/message_consumption.rb +94 -0
  44. data/lib/deimos/consumer.rb +104 -0
  45. data/lib/deimos/instrumentation.rb +76 -0
  46. data/lib/deimos/kafka_message.rb +60 -0
  47. data/lib/deimos/kafka_source.rb +128 -0
  48. data/lib/deimos/kafka_topic_info.rb +102 -0
  49. data/lib/deimos/message.rb +79 -0
  50. data/lib/deimos/metrics/datadog.rb +47 -0
  51. data/lib/deimos/metrics/mock.rb +39 -0
  52. data/lib/deimos/metrics/provider.rb +36 -0
  53. data/lib/deimos/monkey_patches/phobos_cli.rb +35 -0
  54. data/lib/deimos/monkey_patches/phobos_producer.rb +51 -0
  55. data/lib/deimos/poll_info.rb +9 -0
  56. data/lib/deimos/producer.rb +224 -0
  57. data/lib/deimos/railtie.rb +8 -0
  58. data/lib/deimos/schema_backends/avro_base.rb +140 -0
  59. data/lib/deimos/schema_backends/avro_local.rb +30 -0
  60. data/lib/deimos/schema_backends/avro_schema_coercer.rb +119 -0
  61. data/lib/deimos/schema_backends/avro_schema_registry.rb +34 -0
  62. data/lib/deimos/schema_backends/avro_validation.rb +21 -0
  63. data/lib/deimos/schema_backends/base.rb +150 -0
  64. data/lib/deimos/schema_backends/mock.rb +42 -0
  65. data/lib/deimos/shared_config.rb +63 -0
  66. data/lib/deimos/test_helpers.rb +360 -0
  67. data/lib/deimos/tracing/datadog.rb +35 -0
  68. data/lib/deimos/tracing/mock.rb +40 -0
  69. data/lib/deimos/tracing/provider.rb +29 -0
  70. data/lib/deimos/utils/db_poller.rb +150 -0
  71. data/lib/deimos/utils/db_producer.rb +243 -0
  72. data/lib/deimos/utils/deadlock_retry.rb +68 -0
  73. data/lib/deimos/utils/inline_consumer.rb +150 -0
  74. data/lib/deimos/utils/lag_reporter.rb +175 -0
  75. data/lib/deimos/utils/schema_controller_mixin.rb +115 -0
  76. data/lib/deimos/version.rb +5 -0
  77. data/lib/generators/deimos/active_record/templates/migration.rb.tt +28 -0
  78. data/lib/generators/deimos/active_record/templates/model.rb.tt +5 -0
  79. data/lib/generators/deimos/active_record_generator.rb +79 -0
  80. data/lib/generators/deimos/db_backend/templates/migration +25 -0
  81. data/lib/generators/deimos/db_backend/templates/rails3_migration +31 -0
  82. data/lib/generators/deimos/db_backend_generator.rb +48 -0
  83. data/lib/generators/deimos/db_poller/templates/migration +11 -0
  84. data/lib/generators/deimos/db_poller/templates/rails3_migration +16 -0
  85. data/lib/generators/deimos/db_poller_generator.rb +48 -0
  86. data/lib/tasks/deimos.rake +34 -0
  87. data/spec/active_record_batch_consumer_spec.rb +481 -0
  88. data/spec/active_record_consume/batch_slicer_spec.rb +42 -0
  89. data/spec/active_record_consume/schema_model_converter_spec.rb +105 -0
  90. data/spec/active_record_consumer_spec.rb +154 -0
  91. data/spec/active_record_producer_spec.rb +85 -0
  92. data/spec/backends/base_spec.rb +10 -0
  93. data/spec/backends/db_spec.rb +54 -0
  94. data/spec/backends/kafka_async_spec.rb +11 -0
  95. data/spec/backends/kafka_spec.rb +11 -0
  96. data/spec/batch_consumer_spec.rb +256 -0
  97. data/spec/config/configuration_spec.rb +248 -0
  98. data/spec/consumer_spec.rb +209 -0
  99. data/spec/deimos_spec.rb +169 -0
  100. data/spec/generators/active_record_generator_spec.rb +56 -0
  101. data/spec/handlers/my_batch_consumer.rb +10 -0
  102. data/spec/handlers/my_consumer.rb +10 -0
  103. data/spec/kafka_listener_spec.rb +55 -0
  104. data/spec/kafka_source_spec.rb +381 -0
  105. data/spec/kafka_topic_info_spec.rb +111 -0
  106. data/spec/message_spec.rb +19 -0
  107. data/spec/phobos.bad_db.yml +73 -0
  108. data/spec/phobos.yml +77 -0
  109. data/spec/producer_spec.rb +498 -0
  110. data/spec/rake_spec.rb +19 -0
  111. data/spec/schema_backends/avro_base_shared.rb +199 -0
  112. data/spec/schema_backends/avro_local_spec.rb +32 -0
  113. data/spec/schema_backends/avro_schema_registry_spec.rb +32 -0
  114. data/spec/schema_backends/avro_validation_spec.rb +24 -0
  115. data/spec/schema_backends/base_spec.rb +33 -0
  116. data/spec/schemas/com/my-namespace/Generated.avsc +71 -0
  117. data/spec/schemas/com/my-namespace/MyNestedSchema.avsc +62 -0
  118. data/spec/schemas/com/my-namespace/MySchema-key.avsc +13 -0
  119. data/spec/schemas/com/my-namespace/MySchema.avsc +18 -0
  120. data/spec/schemas/com/my-namespace/MySchemaCompound-key.avsc +18 -0
  121. data/spec/schemas/com/my-namespace/MySchemaWithBooleans.avsc +18 -0
  122. data/spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc +33 -0
  123. data/spec/schemas/com/my-namespace/MySchemaWithId.avsc +28 -0
  124. data/spec/schemas/com/my-namespace/MySchemaWithUniqueId.avsc +32 -0
  125. data/spec/schemas/com/my-namespace/Wibble.avsc +43 -0
  126. data/spec/schemas/com/my-namespace/Widget.avsc +27 -0
  127. data/spec/schemas/com/my-namespace/WidgetTheSecond.avsc +27 -0
  128. data/spec/schemas/com/my-namespace/request/CreateTopic.avsc +11 -0
  129. data/spec/schemas/com/my-namespace/request/Index.avsc +11 -0
  130. data/spec/schemas/com/my-namespace/request/UpdateRequest.avsc +11 -0
  131. data/spec/schemas/com/my-namespace/response/CreateTopic.avsc +11 -0
  132. data/spec/schemas/com/my-namespace/response/Index.avsc +11 -0
  133. data/spec/schemas/com/my-namespace/response/UpdateResponse.avsc +11 -0
  134. data/spec/spec_helper.rb +267 -0
  135. data/spec/utils/db_poller_spec.rb +320 -0
  136. data/spec/utils/db_producer_spec.rb +514 -0
  137. data/spec/utils/deadlock_retry_spec.rb +74 -0
  138. data/spec/utils/inline_consumer_spec.rb +31 -0
  139. data/spec/utils/lag_reporter_spec.rb +76 -0
  140. data/spec/utils/platform_schema_validation_spec.rb +0 -0
  141. data/spec/utils/schema_controller_mixin_spec.rb +84 -0
  142. data/support/deimos-solo.png +0 -0
  143. data/support/deimos-with-name-next.png +0 -0
  144. data/support/deimos-with-name.png +0 -0
  145. data/support/flipp-logo.png +0 -0
  146. metadata +551 -0
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'deimos/metrics/provider'
4
+
5
+ module Deimos
6
+ module Metrics
7
+ # A Metrics wrapper class for Datadog.
8
+ class Datadog < Metrics::Provider
9
+ # :nodoc:
10
+ def initialize(config, logger)
11
+ raise 'Metrics config must specify host_ip' if config[:host_ip].nil?
12
+ raise 'Metrics config must specify host_port' if config[:host_port].nil?
13
+ raise 'Metrics config must specify namespace' if config[:namespace].nil?
14
+
15
+ logger.info("DatadogMetricsProvider configured with: #{config}")
16
+ @client = Datadog::Statsd.new(
17
+ config[:host_ip],
18
+ config[:host_port]
19
+ )
20
+ @client.tags = config[:tags]
21
+ @client.namespace = config[:namespace]
22
+ end
23
+
24
+ # :nodoc:
25
+ def increment(metric_name, options={})
26
+ @client.increment(metric_name, options)
27
+ end
28
+
29
+ # :nodoc:
30
+ def gauge(metric_name, count, options={})
31
+ @client.gauge(metric_name, count, options)
32
+ end
33
+
34
+ # :nodoc:
35
+ def histogram(metric_name, count, options={})
36
+ @client.histogram(metric_name, count, options)
37
+ end
38
+
39
+ # :nodoc:
40
+ def time(metric_name, options={})
41
+ @client.time(metric_name, options) do
42
+ yield
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'deimos/metrics/provider'
4
+
5
+ module Deimos
6
+ module Metrics
7
+ # A mock Metrics wrapper which just logs the metrics
8
+ class Mock
9
+ # :nodoc:
10
+ def initialize(logger=nil)
11
+ @logger = logger || Logger.new(STDOUT)
12
+ @logger.info('MockMetricsProvider initialized')
13
+ end
14
+
15
+ # :nodoc:
16
+ def increment(metric_name, options={})
17
+ @logger.info("MockMetricsProvider.increment: #{metric_name}, #{options}")
18
+ end
19
+
20
+ # :nodoc:
21
+ def gauge(metric_name, count, options={})
22
+ @logger.info("MockMetricsProvider.gauge: #{metric_name}, #{count}, #{options}")
23
+ end
24
+
25
+ # :nodoc:
26
+ def histogram(metric_name, count, options={})
27
+ @logger.info("MockMetricsProvider.histogram: #{metric_name}, #{count}, #{options}")
28
+ end
29
+
30
+ # :nodoc:
31
+ def time(metric_name, options={})
32
+ start_time = Time.now
33
+ yield
34
+ total_time = (Time.now - start_time).to_i
35
+ @logger.info("MockMetricsProvider.time: #{metric_name}, #{total_time}, #{options}")
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deimos
4
+ module Metrics
5
+ # Base class for all metrics providers.
6
+ class Provider
7
+ # Send an counter increment metric
8
+ # @param metric_name [String] The name of the counter metric
9
+ # @param options [Hash] Any additional options, e.g. :tags
10
+ def increment(metric_name, options={})
11
+ raise NotImplementedError
12
+ end
13
+
14
+ # Send an counter increment metric
15
+ # @param metric_name [String] The name of the counter metric
16
+ # @param options [Hash] Any additional options, e.g. :tags
17
+ def gauge(metric_name, count, options={})
18
+ raise NotImplementedError
19
+ end
20
+
21
+ # Send an counter increment metric
22
+ # @param metric_name [String] The name of the counter metric
23
+ # @param options [Hash] Any additional options, e.g. :tags
24
+ def histogram(metric_name, count, options={})
25
+ raise NotImplementedError
26
+ end
27
+
28
+ # Time a yielded block, and send a timer metric
29
+ # @param metric_name [String] The name of the metric
30
+ # @param options [Hash] Any additional options, e.g. :tags
31
+ def time(metric_name, options={})
32
+ raise NotImplementedError
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'phobos/cli/start'
4
+
5
+ # :nodoc:
6
+ module Phobos
7
+ # :nodoc:
8
+ module CLI
9
+ # :nodoc:
10
+ class Start
11
+ # :nodoc:
12
+ def validate_listeners!
13
+ Phobos.config.listeners.each do |listener|
14
+ handler = listener.handler
15
+ begin
16
+ handler.constantize
17
+ rescue NameError
18
+ error_exit("Handler '#{handler}' not defined")
19
+ end
20
+
21
+ delivery = listener.delivery
22
+ if delivery.nil?
23
+ Phobos::CLI.logger.warn do
24
+ Hash(message: "Delivery option should be specified, defaulting to 'batch'"\
25
+ ' - specify this option to silence this message')
26
+ end
27
+ elsif !Listener::DELIVERY_OPTS.include?(delivery)
28
+ error_exit("Invalid delivery option '#{delivery}'. Please specify one of: "\
29
+ "#{Listener::DELIVERY_OPTS.join(', ')}")
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'phobos/producer'
4
+
5
+ module Phobos
6
+ module Producer
7
+ # :nodoc:
8
+ class PublicAPI
9
+ # :nodoc:
10
+ def publish(topic, payload, key=nil, partition_key=nil)
11
+ class_producer.publish(topic, payload, key, partition_key)
12
+ end
13
+
14
+ # :nodoc:
15
+ def async_publish(topic, payload, key=nil, partition_key=nil)
16
+ class_producer.async_publish(topic, payload, key, partition_key)
17
+ end
18
+ end
19
+
20
+ # :nodoc:
21
+ module ClassMethods
22
+ # :nodoc:
23
+ class PublicAPI
24
+ # :nodoc:
25
+ def publish(topic, payload, key=nil, partition_key=nil)
26
+ publish_list([{ topic: topic, payload: payload, key: key,
27
+ partition_key: partition_key }])
28
+ end
29
+
30
+ # :nodoc:
31
+ def async_publish(topic, payload, key=nil, partition_key=nil)
32
+ async_publish_list([{ topic: topic, payload: payload, key: key,
33
+ partition_key: partition_key }])
34
+ end
35
+
36
+ private
37
+
38
+ # :nodoc:
39
+ def produce_messages(producer, messages)
40
+ messages.each do |message|
41
+ partition_key = message[:partition_key] || message[:key]
42
+ producer.produce(message[:payload],
43
+ topic: message[:topic],
44
+ key: message[:key],
45
+ partition_key: partition_key)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Deimos
4
+ # ActiveRecord class to record the last time we polled the database.
5
+ # For use with DbPoller.
6
+ class PollInfo < ActiveRecord::Base
7
+ self.table_name = 'deimos_poll_info'
8
+ end
9
+ end
@@ -0,0 +1,224 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'deimos/message'
4
+ require 'deimos/shared_config'
5
+ require 'phobos/producer'
6
+ require 'active_support/notifications'
7
+
8
+ # :nodoc:
9
+ module Deimos
10
+ class << self
11
+ # Run a block without allowing any messages to be produced to Kafka.
12
+ # Optionally add a list of producer classes to limit the disabling to those
13
+ # classes.
14
+ # @param producer_classes [Array<Class>|Class]
15
+ def disable_producers(*producer_classes, &block)
16
+ if producer_classes.any?
17
+ _disable_producer_classes(producer_classes, &block)
18
+ return
19
+ end
20
+
21
+ if Thread.current[:frk_disable_all_producers] # nested disable block
22
+ yield
23
+ return
24
+ end
25
+
26
+ begin
27
+ Thread.current[:frk_disable_all_producers] = true
28
+ yield
29
+ ensure
30
+ Thread.current[:frk_disable_all_producers] = false
31
+ end
32
+ end
33
+
34
+ # :nodoc:
35
+ def _disable_producer_classes(producer_classes)
36
+ Thread.current[:frk_disabled_producers] ||= Set.new
37
+ producers_to_disable = producer_classes -
38
+ Thread.current[:frk_disabled_producers].to_a
39
+ Thread.current[:frk_disabled_producers] += producers_to_disable
40
+ yield
41
+ Thread.current[:frk_disabled_producers] -= producers_to_disable
42
+ end
43
+
44
+ # Are producers disabled? If a class is passed in, check only that class.
45
+ # Otherwise check if the global disable flag is set.
46
+ # @return [Boolean]
47
+ def producers_disabled?(producer_class=nil)
48
+ Thread.current[:frk_disable_all_producers] ||
49
+ Thread.current[:frk_disabled_producers]&.include?(producer_class)
50
+ end
51
+ end
52
+
53
+ # Producer to publish messages to a given kafka topic.
54
+ class Producer
55
+ include SharedConfig
56
+
57
+ MAX_BATCH_SIZE = 500
58
+
59
+ class << self
60
+ # @return [Hash]
61
+ def config
62
+ @config ||= {
63
+ encode_key: true,
64
+ namespace: Deimos.config.producers.schema_namespace
65
+ }
66
+ end
67
+
68
+ # Set the topic.
69
+ # @param topic [String]
70
+ # @return [String] the current topic if no argument given.
71
+ def topic(topic=nil)
72
+ if topic
73
+ config[:topic] = topic
74
+ return
75
+ end
76
+ # accessor
77
+ "#{Deimos.config.producers.topic_prefix}#{config[:topic]}"
78
+ end
79
+
80
+ # Override the default partition key (which is the payload key).
81
+ # @param _payload [Hash] the payload being passed into the produce method.
82
+ # Will include `payload_key` if it is part of the original payload.
83
+ # @return [String]
84
+ def partition_key(_payload)
85
+ nil
86
+ end
87
+
88
+ # Publish the payload to the topic.
89
+ # @param payload [Hash] with an optional payload_key hash key.
90
+ # @param topic [String] if specifying the topic
91
+ def publish(payload, topic: self.topic)
92
+ publish_list([payload], topic: topic)
93
+ end
94
+
95
+ # Publish a list of messages.
96
+ # @param payloads [Hash|Array<Hash>] with optional payload_key hash key.
97
+ # @param sync [Boolean] if given, override the default setting of
98
+ # whether to publish synchronously.
99
+ # @param force_send [Boolean] if true, ignore the configured backend
100
+ # and send immediately to Kafka.
101
+ # @param topic [String] if specifying the topic
102
+ def publish_list(payloads, sync: nil, force_send: false, topic: self.topic)
103
+ return if Deimos.config.kafka.seed_brokers.blank? ||
104
+ Deimos.config.producers.disabled ||
105
+ Deimos.producers_disabled?(self)
106
+
107
+ raise 'Topic not specified. Please specify the topic.' if topic.blank?
108
+
109
+ backend_class = determine_backend_class(sync, force_send)
110
+ Deimos.instrument(
111
+ 'encode_messages',
112
+ producer: self,
113
+ topic: topic,
114
+ payloads: payloads
115
+ ) do
116
+ messages = Array(payloads).map { |p| Deimos::Message.new(p, self) }
117
+ messages.each { |m| _process_message(m, topic) }
118
+ messages.in_groups_of(MAX_BATCH_SIZE, false) do |batch|
119
+ self.produce_batch(backend_class, batch)
120
+ end
121
+ end
122
+ end
123
+
124
+ # @param sync [Boolean]
125
+ # @param force_send [Boolean]
126
+ # @return [Class < Deimos::Backend]
127
+ def determine_backend_class(sync, force_send)
128
+ backend = if force_send
129
+ :kafka
130
+ else
131
+ Deimos.config.producers.backend
132
+ end
133
+ if backend == :kafka_async && sync
134
+ backend = :kafka
135
+ elsif backend == :kafka && sync == false
136
+ backend = :kafka_async
137
+ end
138
+ "Deimos::Backends::#{backend.to_s.classify}".constantize
139
+ end
140
+
141
+ # Send a batch to the backend.
142
+ # @param backend [Class < Deimos::Backend]
143
+ # @param batch [Array<Deimos::Message>]
144
+ def produce_batch(backend, batch)
145
+ backend.publish(producer_class: self, messages: batch)
146
+ end
147
+
148
+ # @return [Deimos::SchemaBackends::Base]
149
+ def encoder
150
+ @encoder ||= Deimos.schema_backend(schema: config[:schema],
151
+ namespace: config[:namespace])
152
+ end
153
+
154
+ # @return [Deimos::SchemaBackends::Base]
155
+ def key_encoder
156
+ @key_encoder ||= Deimos.schema_backend(schema: config[:key_schema],
157
+ namespace: config[:namespace])
158
+ end
159
+
160
+ # Override this in active record producers to add
161
+ # non-schema fields to check for updates
162
+ # @return [Array<String>] fields to check for updates
163
+ def watched_attributes
164
+ self.encoder.schema_fields.map(&:name)
165
+ end
166
+
167
+ private
168
+
169
+ # @param message [Message]
170
+ # @param topic [String]
171
+ def _process_message(message, topic)
172
+ # this violates the Law of Demeter but it has to happen in a very
173
+ # specific order and requires a bunch of methods on the producer
174
+ # to work correctly.
175
+ message.add_fields(encoder.schema_fields.map(&:name))
176
+ message.partition_key = self.partition_key(message.payload)
177
+ message.key = _retrieve_key(message.payload)
178
+ # need to do this before _coerce_fields because that might result
179
+ # in an empty payload which is an *error* whereas this is intended.
180
+ message.payload = nil if message.payload.blank?
181
+ message.coerce_fields(encoder)
182
+ message.encoded_key = _encode_key(message.key)
183
+ message.topic = topic
184
+ message.encoded_payload = if message.payload.nil?
185
+ nil
186
+ else
187
+ encoder.encode(message.payload,
188
+ topic: "#{Deimos.config.producers.topic_prefix}#{config[:topic]}-value")
189
+ end
190
+ end
191
+
192
+ # @param key [Object]
193
+ # @return [String|Object]
194
+ def _encode_key(key)
195
+ if key.nil?
196
+ return nil if config[:no_keys] # no key is fine, otherwise it's a problem
197
+
198
+ raise 'No key given but a key is required! Use `key_config none: true` to avoid using keys.'
199
+ end
200
+ if config[:encode_key] && config[:key_field].nil? &&
201
+ config[:key_schema].nil?
202
+ raise 'No key config given - if you are not encoding keys, please use `key_config plain: true`'
203
+ end
204
+
205
+ if config[:key_field]
206
+ encoder.encode_key(config[:key_field], key, topic: "#{Deimos.config.producers.topic_prefix}#{config[:topic]}-key")
207
+ elsif config[:key_schema]
208
+ key_encoder.encode(key, topic: "#{Deimos.config.producers.topic_prefix}#{config[:topic]}-key")
209
+ else
210
+ key
211
+ end
212
+ end
213
+
214
+ # @param payload [Hash]
215
+ # @return [String]
216
+ def _retrieve_key(payload)
217
+ key = payload.delete(:payload_key)
218
+ return key if key
219
+
220
+ config[:key_field] ? payload[config[:key_field]] : nil
221
+ end
222
+ end
223
+ end
224
+ end