deimos-ruby 1.16.1 → 1.16.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile +6 -0
  5. data/README.md +22 -0
  6. data/lib/deimos/active_record_consume/batch_consumption.rb +7 -2
  7. data/lib/deimos/active_record_consume/batch_slicer.rb +2 -0
  8. data/lib/deimos/active_record_consume/message_consumption.rb +8 -4
  9. data/lib/deimos/active_record_consumer.rb +7 -4
  10. data/lib/deimos/active_record_producer.rb +10 -0
  11. data/lib/deimos/backends/base.rb +4 -2
  12. data/lib/deimos/backends/kafka.rb +1 -0
  13. data/lib/deimos/backends/kafka_async.rb +1 -0
  14. data/lib/deimos/config/configuration.rb +4 -0
  15. data/lib/deimos/config/phobos_config.rb +2 -1
  16. data/lib/deimos/consume/batch_consumption.rb +8 -1
  17. data/lib/deimos/consume/message_consumption.rb +4 -1
  18. data/lib/deimos/instrumentation.rb +11 -4
  19. data/lib/deimos/kafka_message.rb +1 -0
  20. data/lib/deimos/kafka_source.rb +5 -0
  21. data/lib/deimos/kafka_topic_info.rb +4 -0
  22. data/lib/deimos/message.rb +19 -2
  23. data/lib/deimos/metrics/datadog.rb +2 -1
  24. data/lib/deimos/metrics/mock.rb +2 -2
  25. data/lib/deimos/metrics/provider.rb +6 -0
  26. data/lib/deimos/monkey_patches/phobos_cli.rb +1 -1
  27. data/lib/deimos/monkey_patches/phobos_producer.rb +1 -0
  28. data/lib/deimos/producer.rb +12 -6
  29. data/lib/deimos/schema_backends/base.rb +31 -17
  30. data/lib/deimos/schema_backends/mock.rb +2 -2
  31. data/lib/deimos/schema_class/base.rb +9 -5
  32. data/lib/deimos/schema_class/enum.rb +4 -2
  33. data/lib/deimos/schema_class/record.rb +12 -6
  34. data/lib/deimos/shared_config.rb +6 -2
  35. data/lib/deimos/test_helpers.rb +21 -4
  36. data/lib/deimos/tracing/datadog.rb +1 -1
  37. data/lib/deimos/tracing/mock.rb +4 -3
  38. data/lib/deimos/tracing/provider.rb +5 -0
  39. data/lib/deimos/utils/db_poller.rb +9 -1
  40. data/lib/deimos/utils/db_producer.rb +14 -2
  41. data/lib/deimos/utils/deadlock_retry.rb +3 -0
  42. data/lib/deimos/utils/inline_consumer.rb +14 -6
  43. data/lib/deimos/utils/lag_reporter.rb +11 -0
  44. data/lib/deimos/utils/schema_controller_mixin.rb +8 -0
  45. data/lib/deimos/version.rb +1 -1
  46. data/lib/deimos.rb +3 -2
  47. data/lib/generators/deimos/active_record_generator.rb +1 -1
  48. data/lib/generators/deimos/db_backend_generator.rb +1 -0
  49. data/lib/generators/deimos/db_poller_generator.rb +1 -0
  50. data/lib/generators/deimos/schema_class/templates/schema_record.rb.tt +13 -5
  51. data/lib/generators/deimos/schema_class_generator.rb +51 -24
  52. data/rbs_collection.lock.yaml +176 -0
  53. data/rbs_collection.yaml +15 -0
  54. data/regenerate_test_schema_classes.rb +68 -0
  55. data/sig/avro.rbs +14 -0
  56. data/sig/defs.rbs +1859 -0
  57. data/sig/fig_tree.rbs +2 -0
  58. data/spec/active_record_producer_spec.rb +24 -0
  59. data/spec/generators/schema_class/my_schema_spec.rb +16 -0
  60. data/spec/generators/schema_class/my_schema_with_circular_reference_spec.rb +1 -1
  61. data/spec/generators/schema_class/my_schema_with_complex_types_spec.rb +32 -24
  62. data/spec/producer_spec.rb +11 -11
  63. data/spec/schemas/{generated.rb → my_namespace/generated.rb} +28 -32
  64. data/spec/schemas/{my_nested_schema.rb → my_namespace/my_nested_schema.rb} +23 -16
  65. data/spec/schemas/{my_schema.rb → my_namespace/my_schema.rb} +12 -5
  66. data/spec/schemas/my_namespace/my_schema_compound_key.rb +41 -0
  67. data/spec/schemas/my_namespace/my_schema_id_key.rb +36 -0
  68. data/spec/schemas/{my_schema_key.rb → my_namespace/my_schema_key.rb} +3 -3
  69. data/spec/schemas/my_namespace/my_schema_with_boolean.rb +41 -0
  70. data/spec/schemas/{my_schema_with_circular_reference.rb → my_namespace/my_schema_with_circular_reference.rb} +15 -10
  71. data/spec/schemas/{my_schema_with_complex_type.rb → my_namespace/my_schema_with_complex_type.rb} +34 -49
  72. data/spec/schemas/my_namespace/my_schema_with_date_time.rb +56 -0
  73. data/spec/schemas/my_namespace/my_schema_with_id.rb +51 -0
  74. data/spec/schemas/my_namespace/my_schema_with_unique_id.rb +56 -0
  75. data/spec/schemas/my_namespace/wibble.rb +76 -0
  76. data/spec/schemas/my_namespace/widget.rb +56 -0
  77. data/spec/schemas/my_namespace/widget_the_second.rb +56 -0
  78. data/spec/schemas/request/create_topic.rb +36 -0
  79. data/spec/schemas/request/index.rb +36 -0
  80. data/spec/schemas/request/update_request.rb +36 -0
  81. data/spec/schemas/response/create_topic.rb +36 -0
  82. data/spec/schemas/response/index.rb +36 -0
  83. data/spec/schemas/response/update_response.rb +36 -0
  84. data/spec/snapshots/consumers-no-nest.snap +93 -86
  85. data/spec/snapshots/consumers.snap +94 -87
  86. data/spec/snapshots/consumers_and_producers-no-nest.snap +108 -87
  87. data/spec/snapshots/consumers_and_producers.snap +109 -88
  88. data/spec/snapshots/consumers_circular-no-nest.snap +93 -86
  89. data/spec/snapshots/consumers_circular.snap +94 -87
  90. data/spec/snapshots/consumers_complex_types-no-nest.snap +93 -86
  91. data/spec/snapshots/consumers_complex_types.snap +94 -87
  92. data/spec/snapshots/consumers_nested-no-nest.snap +93 -86
  93. data/spec/snapshots/consumers_nested.snap +94 -87
  94. data/spec/snapshots/namespace_folders.snap +111 -90
  95. data/spec/snapshots/producers_with_key-no-nest.snap +94 -87
  96. data/spec/snapshots/producers_with_key.snap +95 -88
  97. data/spec/spec_helper.rb +2 -1
  98. metadata +53 -15
@@ -8,8 +8,11 @@ module Deimos
8
8
  include Phobos::Producer
9
9
  attr_accessor :id, :current_topic
10
10
 
11
+ # @return [Integer]
11
12
  BATCH_SIZE = 1000
13
+ # @return [Integer]
12
14
  DELETE_BATCH_SIZE = 10
15
+ # @return [Integer]
13
16
  MAX_DELETE_ATTEMPTS = 3
14
17
 
15
18
  # @param logger [Logger]
@@ -19,12 +22,13 @@ module Deimos
19
22
  @logger.push_tags("DbProducer #{@id}") if @logger.respond_to?(:push_tags)
20
23
  end
21
24
 
22
- # @return [Deimos::DbProducerConfig]
25
+ # @return [FigTree]
23
26
  def config
24
27
  Deimos.config.db_producer
25
28
  end
26
29
 
27
30
  # Start the poll.
31
+ # @return [void]
28
32
  def start
29
33
  @logger.info('Starting...')
30
34
  @signal_to_stop = false
@@ -40,12 +44,14 @@ module Deimos
40
44
  end
41
45
 
42
46
  # Stop the poll.
47
+ # @return [void]
43
48
  def stop
44
49
  @logger.info('Received signal to stop')
45
50
  @signal_to_stop = true
46
51
  end
47
52
 
48
53
  # Complete one loop of processing all messages in the DB.
54
+ # @return [void]
49
55
  def process_next_messages
50
56
  topics = retrieve_topics
51
57
  @logger.info("Found topics: #{topics}")
@@ -80,6 +86,7 @@ module Deimos
80
86
  end
81
87
 
82
88
  # Process a single batch in a topic.
89
+ # @return [void]
83
90
  def process_topic_batch
84
91
  messages = retrieve_messages
85
92
  return false if messages.empty?
@@ -111,6 +118,7 @@ module Deimos
111
118
  end
112
119
 
113
120
  # @param messages [Array<Deimos::KafkaMessage>]
121
+ # @return [void]
114
122
  def delete_messages(messages)
115
123
  attempts = 1
116
124
  begin
@@ -137,6 +145,7 @@ module Deimos
137
145
  end
138
146
 
139
147
  # @param messages [Array<Deimos::KafkaMessage>]
148
+ # @return [void]
140
149
  def log_messages(messages)
141
150
  return if config.log_topics != :all && !config.log_topics.include?(@current_topic)
142
151
 
@@ -146,7 +155,8 @@ module Deimos
146
155
  end
147
156
  end
148
157
 
149
- # Send metrics to Datadog.
158
+ # Send metrics related to pending messages.
159
+ # @return [void]
150
160
  def send_pending_metrics
151
161
  metrics = Deimos.config.metrics
152
162
  return unless metrics
@@ -185,6 +195,7 @@ module Deimos
185
195
  # Shut down the sync producer if we have to. Phobos will automatically
186
196
  # create a new one. We should call this if the producer can be in a bad
187
197
  # state and e.g. we need to clear the buffer.
198
+ # @return [void]
188
199
  def shutdown_producer
189
200
  if self.class.producer.respond_to?(:sync_producer_shutdown) # Phobos 1.8.3
190
201
  self.class.producer.sync_producer_shutdown
@@ -194,6 +205,7 @@ module Deimos
194
205
  # Produce messages in batches, reducing the size 1/10 if the batch is too
195
206
  # large. Does not retry batches of messages that have already been sent.
196
207
  # @param batch [Array<Hash>]
208
+ # @return [void]
197
209
  def produce_messages(batch)
198
210
  batch_size = batch.size
199
211
  current_index = 0
@@ -7,9 +7,11 @@ module Deimos
7
7
  class DeadlockRetry
8
8
  class << self
9
9
  # Maximum number of times to retry the block after encountering a deadlock
10
+ # @return [Integer]
10
11
  RETRY_COUNT = 2
11
12
 
12
13
  # Need to match on error messages to support older Rails versions
14
+ # @return [Array<String>]
13
15
  DEADLOCK_MESSAGES = [
14
16
  # MySQL
15
17
  'Deadlock found when trying to get lock',
@@ -28,6 +30,7 @@ module Deimos
28
30
  # from retrying at the same time.
29
31
  # @param tags [Array] Tags to attach when logging and reporting metrics.
30
32
  # @yield Yields to the block that may deadlock.
33
+ # @return [void]
31
34
  def wrap(tags=[])
32
35
  count = RETRY_COUNT
33
36
 
@@ -6,10 +6,12 @@ module Deimos
6
6
  module Utils
7
7
  # Listener that can seek to get the last X messages in a topic.
8
8
  class SeekListener < Phobos::Listener
9
+ # @return [Integer]
9
10
  MAX_SEEK_RETRIES = 3
11
+ # @return [Integer]
10
12
  attr_accessor :num_messages
11
13
 
12
- # :nodoc:
14
+ # @return [void]
13
15
  def start_listener
14
16
  @num_messages ||= 10
15
17
  @consumer = create_kafka_consumer
@@ -45,17 +47,20 @@ module Deimos
45
47
 
46
48
  cattr_accessor :total_messages
47
49
 
48
- # @param klass [Class < Deimos::Consumer]
50
+ # @param klass [Class<Deimos::Consumer>]
51
+ # @return [void]
49
52
  def self.config_class=(klass)
50
53
  self.config.merge!(klass.config)
51
54
  end
52
55
 
53
- # :nodoc:
56
+ # @param _kafka_client [Kafka::Client]
57
+ # @return [void]
54
58
  def self.start(_kafka_client)
55
59
  self.total_messages = []
56
60
  end
57
61
 
58
- # :nodoc:
62
+ # @param payload [Hash]
63
+ # @param metadata [Hash]
59
64
  def consume(payload, metadata)
60
65
  self.class.total_messages << {
61
66
  key: metadata[:key],
@@ -66,18 +71,20 @@ module Deimos
66
71
 
67
72
  # Class which can process/consume messages inline.
68
73
  class InlineConsumer
74
+ # @return [Integer]
69
75
  MAX_MESSAGE_WAIT_TIME = 1.second
76
+ # @return [Integer]
70
77
  MAX_TOPIC_WAIT_TIME = 10.seconds
71
78
 
72
79
  # Get the last X messages from a topic. You can specify a subclass of
73
80
  # Deimos::Consumer or Deimos::Producer, or provide the
74
81
  # schema, namespace and key_config directly.
75
82
  # @param topic [String]
76
- # @param config_class [Class < Deimos::Consumer|Deimos::Producer>]
83
+ # @param config_class [Class<Deimos::Consumer>,Class<Deimos::Producer>]
77
84
  # @param schema [String]
78
85
  # @param namespace [String]
79
86
  # @param key_config [Hash]
80
- # @param num_messages [Number]
87
+ # @param num_messages [Integer]
81
88
  # @return [Array<Hash>]
82
89
  def self.get_messages_for(topic:, schema: nil, namespace: nil, key_config: nil,
83
90
  config_class: nil, num_messages: 10)
@@ -106,6 +113,7 @@ module Deimos
106
113
  # @param frk_consumer [Class]
107
114
  # @param num_messages [Integer] If this number is >= the number
108
115
  # of messages in the topic, all messages will be consumed.
116
+ # @return [void]
109
117
  def self.consume(topic:, frk_consumer:, num_messages: 10)
110
118
  listener = SeekListener.new(
111
119
  handler: frk_consumer,
@@ -24,6 +24,7 @@ module Deimos
24
24
 
25
25
  # @param topic [String]
26
26
  # @param partition [Integer]
27
+ # @return [void]
27
28
  def report_lag(topic, partition)
28
29
  self.topics[topic.to_s] ||= Topic.new(topic, self)
29
30
  self.topics[topic.to_s].report_lag(partition)
@@ -32,6 +33,7 @@ module Deimos
32
33
  # @param topic [String]
33
34
  # @param partition [Integer]
34
35
  # @param offset [Integer]
36
+ # @return [void]
35
37
  def assign_current_offset(topic, partition, offset)
36
38
  self.topics[topic.to_s] ||= Topic.new(topic, self)
37
39
  self.topics[topic.to_s].assign_current_offset(partition, offset)
@@ -56,11 +58,15 @@ module Deimos
56
58
  end
57
59
 
58
60
  # @param partition [Integer]
61
+ # @param offset [Integer]
62
+ # @return [void]
59
63
  def assign_current_offset(partition, offset)
60
64
  self.partition_current_offsets[partition.to_i] = offset
61
65
  end
62
66
 
63
67
  # @param partition [Integer]
68
+ # @param offset [Integer]
69
+ # @return [Integer]
64
70
  def compute_lag(partition, offset)
65
71
  begin
66
72
  client = Phobos.create_kafka_client
@@ -74,6 +80,7 @@ module Deimos
74
80
  end
75
81
 
76
82
  # @param partition [Integer]
83
+ # @return [void]
77
84
  def report_lag(partition)
78
85
  current_offset = self.partition_current_offsets[partition.to_i]
79
86
  return unless current_offset
@@ -94,6 +101,7 @@ module Deimos
94
101
 
95
102
  class << self
96
103
  # Reset all group information.
104
+ # @return [void]
97
105
  def reset
98
106
  @groups = {}
99
107
  end
@@ -103,6 +111,7 @@ module Deimos
103
111
  # topic = event.payload.fetch(:topic)
104
112
  # partition = event.payload.fetch(:partition)
105
113
  # @param payload [Hash]
114
+ # @return [void]
106
115
  def message_processed(payload)
107
116
  offset = payload[:offset] || payload[:last_offset]
108
117
  topic = payload[:topic]
@@ -116,6 +125,7 @@ module Deimos
116
125
  end
117
126
 
118
127
  # @param payload [Hash]
128
+ # @return [void]
119
129
  def offset_seek(payload)
120
130
  offset = payload[:offset]
121
131
  topic = payload[:topic]
@@ -129,6 +139,7 @@ module Deimos
129
139
  end
130
140
 
131
141
  # @param payload [Hash]
142
+ # @return [void]
132
143
  def heartbeat(payload)
133
144
  group = payload[:group_id]
134
145
  synchronize do
@@ -31,6 +31,7 @@ module Deimos
31
31
  # @param kwactions [String]
32
32
  # @param request [String]
33
33
  # @param response [String]
34
+ # @return [void]
34
35
  def schemas(*actions, request: nil, response: nil, **kwactions)
35
36
  actions.each do |action|
36
37
  request ||= action.to_s.titleize
@@ -49,6 +50,7 @@ module Deimos
49
50
 
50
51
  # Set the namespace for both requests and responses.
51
52
  # @param name [String]
53
+ # @return [void]
52
54
  def namespace(name)
53
55
  request_namespace(name)
54
56
  response_namespace(name)
@@ -56,12 +58,14 @@ module Deimos
56
58
 
57
59
  # Set the namespace for requests.
58
60
  # @param name [String]
61
+ # @return [void]
59
62
  def request_namespace(name)
60
63
  namespaces[:request] = name
61
64
  end
62
65
 
63
66
  # Set the namespace for repsonses.
64
67
  # @param name [String]
68
+ # @return [void]
65
69
  def response_namespace(name)
66
70
  namespaces[:response] = name
67
71
  end
@@ -94,6 +98,7 @@ module Deimos
94
98
  end
95
99
 
96
100
  # Decode the payload with the parameters.
101
+ # @return [void]
97
102
  def decode_schema
98
103
  namespace, schema = parse_namespace(:request)
99
104
  decoder = Deimos.schema_backend(schema: schema, namespace: namespace)
@@ -109,6 +114,9 @@ module Deimos
109
114
 
110
115
  # Render a hash into a payload as specified by the configured schema and namespace.
111
116
  # @param payload [Hash]
117
+ # @param schema [String]
118
+ # @param namespace [String]
119
+ # @return [void]
112
120
  def render_schema(payload, schema: nil, namespace: nil)
113
121
  namespace, schema = parse_namespace(:response) if !schema && !namespace
114
122
  encoder = Deimos.schema_backend(schema: schema, namespace: namespace)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Deimos
4
- VERSION = '1.16.1'
4
+ VERSION = '1.16.4'
5
5
  end
data/lib/deimos.rb CHANGED
@@ -45,7 +45,7 @@ require 'erb'
45
45
  # Parent module.
46
46
  module Deimos
47
47
  class << self
48
- # @return [Class < Deimos::SchemaBackends::Base]
48
+ # @return [Class<Deimos::SchemaBackends::Base>]
49
49
  def schema_backend_class
50
50
  backend = Deimos.config.schema.backend.to_s
51
51
 
@@ -54,7 +54,7 @@ module Deimos
54
54
  "Deimos::SchemaBackends::#{backend.classify}".constantize
55
55
  end
56
56
 
57
- # @param schema [String|Symbol]
57
+ # @param schema [String, Symbol]
58
58
  # @param namespace [String]
59
59
  # @return [Deimos::SchemaBackends::Base]
60
60
  def schema_backend(schema:, namespace:)
@@ -81,6 +81,7 @@ module Deimos
81
81
 
82
82
  # Start the DB producers to send Kafka messages.
83
83
  # @param thread_count [Integer] the number of threads to start.
84
+ # @return [void]
84
85
  def start_db_backend!(thread_count: 1)
85
86
  Sigurd.exit_on_signal = true
86
87
  if self.config.producers.backend != :db
@@ -69,7 +69,7 @@ module Deimos
69
69
  end
70
70
 
71
71
  desc 'Generate migration for a table based on an existing schema.'
72
- # :nodoc:
72
+ # @return [void]
73
73
  def generate
74
74
  migration_template('migration.rb', "db/migrate/create_#{table_name.underscore}.rb")
75
75
  template('model.rb', "app/models/#{table_name.underscore.singularize}.rb")
@@ -34,6 +34,7 @@ module Deimos
34
34
  end
35
35
 
36
36
  # Main method to create all the necessary files
37
+ # @return [void]
37
38
  def generate
38
39
  if Rails.version < '4'
39
40
  migration_template('rails3_migration',
@@ -34,6 +34,7 @@ module Deimos
34
34
  end
35
35
 
36
36
  # Main method to create all the necessary files
37
+ # @return [void]
37
38
  def generate
38
39
  if Rails.version < '4'
39
40
  migration_template('rails3_migration',
@@ -20,7 +20,7 @@
20
20
  <%- if @field_assignments.select{ |h| !h[:is_schema_class] }.any? -%>
21
21
  ### Attribute Accessors ###
22
22
  <%- @field_assignments.select{ |h| !h[:is_schema_class] }.each do |method_definition| -%>
23
- # @param <%= method_definition[:method_argument] %> [<%= method_definition[:deimos_type] %>]
23
+ # @return [<%= method_definition[:deimos_type] %>]
24
24
  attr_accessor :<%= method_definition[:field].name %>
25
25
  <%- end -%>
26
26
 
@@ -28,14 +28,14 @@
28
28
  <%- if @field_assignments.select{ |h| h[:is_schema_class] }.any? -%>
29
29
  ### Attribute Writers ###
30
30
  <%- @field_assignments.select{ |h| h[:is_schema_class] }.each do |method_definition| -%>
31
- # @param <%= method_definition[:method_argument] %> [<%= method_definition[:deimos_type] %>]
31
+ # @return [<%= method_definition[:deimos_type] %>]
32
32
  def <%= method_definition[:field].name %>=(<%= method_definition[:method_argument] %>)
33
33
  <%- if method_definition[:field_type] == :array -%>
34
- @<%= method_definition[:field].name %> = values.map do |value|
34
+ @<%= method_definition[:field].name %> = values&.map do |value|
35
35
  <%= method_definition[:field_initialization] %>
36
36
  end
37
37
  <%- elsif method_definition[:field_type] == :map -%>
38
- @<%= method_definition[:field].name %> = values.transform_values do |value|
38
+ @<%= method_definition[:field].name %> = values&.transform_values do |value|
39
39
  <%= method_definition[:field_initialization] %>
40
40
  end
41
41
  <%- else -%>
@@ -62,7 +62,15 @@
62
62
  def namespace
63
63
  '<%= @current_schema.namespace %>'
64
64
  end
65
-
65
+ <%- if @tombstone_assignment %>
66
+ def self.tombstone(key)
67
+ record = self.allocate
68
+ <%- if @tombstone_assignment.present? -%>
69
+ <%= @tombstone_assignment %>
70
+ <%- end -%>
71
+ record
72
+ end
73
+ <%- end %>
66
74
  # @override
67
75
  def as_json(_opts={})
68
76
  {
@@ -11,11 +11,17 @@ module Deimos
11
11
  # Generator for Schema Classes used for the IDE and consumer/producer interfaces
12
12
  class SchemaClassGenerator < Rails::Generators::Base
13
13
 
14
+ # @return [Array<Symbol>]
14
15
  SPECIAL_TYPES = %i(record enum).freeze
16
+ # @return [String]
15
17
  INITIALIZE_WHITESPACE = "\n#{' ' * 19}"
18
+ # @return [Array<String>]
16
19
  IGNORE_DEFAULTS = %w(message_id timestamp).freeze
20
+ # @return [String]
17
21
  SCHEMA_CLASS_FILE = 'schema_class.rb'
22
+ # @return [String]
18
23
  SCHEMA_RECORD_PATH = File.expand_path('schema_class/templates/schema_record.rb.tt', __dir__).freeze
24
+ # @return [String]
19
25
  SCHEMA_ENUM_PATH = File.expand_path('schema_class/templates/schema_enum.rb.tt', __dir__).freeze
20
26
 
21
27
  source_root File.expand_path('schema_class/templates', __dir__)
@@ -41,16 +47,17 @@ module Deimos
41
47
  # Deimos Consumer or Producer Configuration object
42
48
  # @param schema_name [String]
43
49
  # @param namespace [String]
44
- # @param key_schema_name [String,nil]
45
- def generate_classes(schema_name, namespace, key_schema_name)
50
+ # @param key_config [Hash,nil]
51
+ # @return [void]
52
+ def generate_classes(schema_name, namespace, key_config)
46
53
  schema_base = Deimos.schema_backend(schema: schema_name, namespace: namespace)
47
54
  schema_base.load_schema
48
- if key_schema_name.present?
49
- key_schema_base = Deimos.schema_backend(schema: key_schema_name, namespace: namespace)
55
+ if key_config&.dig(:schema)
56
+ key_schema_base = Deimos.schema_backend(schema: key_config[:schema], namespace: namespace)
50
57
  key_schema_base.load_schema
51
- generate_class_from_schema_base(key_schema_base)
58
+ generate_class_from_schema_base(key_schema_base, key_config: nil)
52
59
  end
53
- generate_class_from_schema_base(schema_base, key_schema_base: key_schema_base)
60
+ generate_class_from_schema_base(schema_base, key_config: key_config)
54
61
  end
55
62
 
56
63
  # @param schema [Avro::Schema::NamedSchema]
@@ -83,8 +90,9 @@ module Deimos
83
90
  end
84
91
 
85
92
  # @param schema_base [Deimos::SchemaBackends::Base]
86
- # @param key_schema_base[Avro::Schema::NamedSchema]
87
- def generate_class_from_schema_base(schema_base, key_schema_base: nil)
93
+ # @param key_config [Hash,nil]
94
+ # @return [void]
95
+ def generate_class_from_schema_base(schema_base, key_config: nil)
88
96
  @discovered_schemas = Set.new
89
97
  @sub_schema_templates = []
90
98
  schemas = collect_all_schemas(schema_base.schema_store.schemas.values)
@@ -93,11 +101,11 @@ module Deimos
93
101
  sub_schemas = schemas.reject { |s| s.name == schema_base.schema }.sort_by(&:name)
94
102
  if Deimos.config.schema.nest_child_schemas
95
103
  @sub_schema_templates = sub_schemas.map do |schema|
96
- _generate_class_template_from_schema(schema)
104
+ _generate_class_template_from_schema(schema, nil)
97
105
  end
98
- write_file(main_schema, key_schema_base)
106
+ write_file(main_schema, key_config)
99
107
  else
100
- write_file(main_schema, key_schema_base)
108
+ write_file(main_schema, key_config)
101
109
  sub_schemas.each do |schema|
102
110
  write_file(schema, nil)
103
111
  end
@@ -105,9 +113,10 @@ module Deimos
105
113
  end
106
114
 
107
115
  # @param schema [Avro::Schema::NamedSchema]
108
- # @param key_schema_base [Avro::Schema::NamedSchema, nil]
109
- def write_file(schema, key_schema_base)
110
- class_template = _generate_class_template_from_schema(schema, key_schema_base)
116
+ # @param key_config [Hash,nil]
117
+ # @return [void]
118
+ def write_file(schema, key_config)
119
+ class_template = _generate_class_template_from_schema(schema, key_config)
111
120
  @modules = Utils::SchemaClass.modules_for(schema.namespace)
112
121
  @main_class_definition = class_template
113
122
 
@@ -143,7 +152,7 @@ module Deimos
143
152
  end
144
153
 
145
154
  desc 'Generate a class based on configured consumer and producers.'
146
- # :nodoc:
155
+ # @return [void]
147
156
  def generate
148
157
  _validate
149
158
  Rails.logger.info("Generating schemas from Deimos.config to #{Deimos.config.schema.generated_class_path}")
@@ -154,7 +163,7 @@ module Deimos
154
163
  key_schema_name = config.key_config[:schema]
155
164
  found_schemas.add("#{namespace}.#{schema_name}")
156
165
  found_schemas.add("#{namespace}.#{key_schema_name}") if key_schema_name
157
- generate_classes(schema_name, namespace, key_schema_name)
166
+ generate_classes(schema_name, namespace, config.key_config)
158
167
  end
159
168
 
160
169
  Deimos.config.consumer_objects.each do |config|
@@ -163,7 +172,7 @@ module Deimos
163
172
  key_schema_name = config.key_config[:schema]
164
173
  found_schemas.add("#{namespace}.#{schema_name}")
165
174
  found_schemas.add("#{namespace}.#{key_schema_name}") if key_schema_name
166
- generate_classes(schema_name, namespace, key_schema_name)
175
+ generate_classes(schema_name, namespace, config.key_config)
167
176
  end
168
177
 
169
178
  generate_from_schema_files(found_schemas)
@@ -191,10 +200,10 @@ module Deimos
191
200
  end
192
201
 
193
202
  # @param schema[Avro::Schema::NamedSchema]
194
- # @param key_schema_base[Avro::Schema::NamedSchema]
203
+ # @param key_config[Hash,nil]
195
204
  # @return [String]
196
- def _generate_class_template_from_schema(schema, key_schema_base=nil)
197
- _set_instance_variables(schema, key_schema_base)
205
+ def _generate_class_template_from_schema(schema, key_config)
206
+ _set_instance_variables(schema, key_config)
198
207
 
199
208
  temp = schema.is_a?(Avro::Schema::RecordSchema) ? _record_class_template : _enum_class_template
200
209
  res = ERB.new(temp, nil, '-')
@@ -202,20 +211,38 @@ module Deimos
202
211
  end
203
212
 
204
213
  # @param schema[Avro::Schema::NamedSchema]
205
- # @param key_schema_base[Avro::Schema::NamedSchema]
206
- def _set_instance_variables(schema, key_schema_base=nil)
214
+ # @param key_config [Hash,nil]
215
+ def _set_instance_variables(schema, key_config)
207
216
  schema_is_record = schema.is_a?(Avro::Schema::RecordSchema)
208
217
  @current_schema = schema
209
218
  return unless schema_is_record
210
219
 
211
220
  @fields = fields(schema)
212
- if key_schema_base.present?
221
+ key_schema = nil
222
+ if key_config&.dig(:schema)
223
+ key_schema_base = Deimos.schema_backend(schema: key_config[:schema], namespace: schema.namespace)
213
224
  key_schema_base.load_schema
214
225
  key_schema = key_schema_base.schema_store.schemas.values.first
215
226
  @fields << Deimos::SchemaField.new('payload_key', key_schema, [], nil)
216
227
  end
217
228
  @initialization_definition = _initialization_definition
218
229
  @field_assignments = _field_assignments
230
+ @tombstone_assignment = _tombstone_assignment(key_config, key_schema)
231
+ end
232
+
233
+ def _tombstone_assignment(key_config, key_schema)
234
+ return nil unless key_config
235
+
236
+ if key_config[:plain]
237
+ "record.tombstone_key = key"
238
+ elsif key_config[:field]
239
+ "record.tombstone_key = key\n record.#{key_config[:field]} = key"
240
+ elsif key_schema
241
+ field_base_type = _field_type(key_schema)
242
+ "record.tombstone_key = #{field_base_type}.initialize_from_value(key)\n record.payload_key = key"
243
+ else
244
+ ''
245
+ end
219
246
  end
220
247
 
221
248
  # Defines the initialization method for Schema Records with one keyword argument per line
@@ -234,7 +261,7 @@ module Deimos
234
261
  "#{result})"
235
262
  end
236
263
 
237
- # @param [SchemaField]
264
+ # @param field [SchemaField]
238
265
  # @return [String]
239
266
  def _field_default(field)
240
267
  default = field.default