deimos-ruby 1.23.2 → 1.23.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0c3a1e7084ccdf781b9a826de555c98661f564c3ecaaf8daf80427d59f91c6e
4
- data.tar.gz: 995449f489eb5bc76e870e2666c53a48866d54202b98d508c278f393c604d412
3
+ metadata.gz: 42d51126a6bf86b0aa338798c9b9a4b479154eda722394940df0bbc8a23e3947
4
+ data.tar.gz: 8d6c27244277078ea3b5d2a23440071aba43db3938c43cbbfe4fef27db207556
5
5
  SHA512:
6
- metadata.gz: a203d1c8d44f90f512ea4a4c3fa03d524a6fde8afad3e1683a5a1c7c544e21e159bdd61cde92f0a256465b06bdb30ae6472ae415afe0d988afa9a8eb217bd1b8
7
- data.tar.gz: c510ed78c61d2ed42de36ba631d69070f9d9a9406cedb15bb7c0182cb984c0a13c25887b633467c819432809bf1aa73b48e3ce81589f1b9f82d6519588e1c043
6
+ metadata.gz: 86d98c4e4cc84a380b69196c4d04c51a6a8aaaa05601e2d7deac536495d7c689c987555e23e1bcafb895dc78e24492c9c0b174ee273c0859c9d76795a510d154
7
+ data.tar.gz: 8e7875b92bb043c95721a9a12747f6f6727bc225f1802f5d6a6ba34ee4757884347aaa42b3050d9b77f668b7ebd2654aa322cd46dea3c426d140a191c19f7fb0
data/CHANGELOG.md CHANGED
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## UNRELEASED
9
9
 
10
+ # 1.23.3 - 2024-01-25
11
+ - Feature: Add configuration to skip messages that are too large to publish via DB poller.
12
+
10
13
  # 1.23.2 - 2024-01-22
11
14
  - Fix: Send a `publish_error` metric for errors other than `DeliveryFailed`.
12
15
 
@@ -500,6 +500,9 @@ module Deimos # rubocop:disable Metrics/ModuleLength
500
500
  # The number of times to retry production when encountering a *non-Kafka* error. Set to nil
501
501
  # for infinite retries.
502
502
  setting :retries, 1
503
+ # If true, rather than shutting down when finding a message that is too large, log an
504
+ # error and skip it.
505
+ setting :skip_too_large_messages, false
503
506
  # Amount of time, in seconds, to wait before catching updates, to allow transactions
504
507
  # to complete but still pick up the right records. Should only be set for time-based mode.
505
508
  setting :delay_time, 2
@@ -43,6 +43,32 @@ module Deimos
43
43
 
44
44
  # This module listens to events published by RubyKafka.
45
45
  module KafkaListener
46
+ # @param exception [Exception]
47
+ def self.handle_exception_with_messages(exception)
48
+ messages = exception.failed_messages
49
+ messages.group_by(&:topic).each do |topic, batch|
50
+ producer = Deimos::Producer.descendants.find { |c| c.topic == topic }
51
+ next if batch.empty? || !producer
52
+
53
+ decoder = Deimos.schema_backend(schema: producer.config[:schema],
54
+ namespace: producer.config[:namespace])
55
+ payloads = batch.map { |m| decoder.decode(m.value) }
56
+
57
+ Deimos.config.metrics&.increment(
58
+ 'publish_error',
59
+ tags: %W(topic:#{topic}),
60
+ by: payloads.size
61
+ )
62
+ Deimos.instrument(
63
+ 'produce_error',
64
+ producer: producer,
65
+ topic: topic,
66
+ exception_object: exception,
67
+ payloads: payloads
68
+ )
69
+ end
70
+ end
71
+
46
72
  # Listens for any exceptions that happen during publishing and re-publishes
47
73
  # as a Deimos event.
48
74
  # @param event [ActiveSupport::Notifications::Event]
@@ -52,28 +78,7 @@ module Deimos
52
78
  return unless exception
53
79
 
54
80
  if exception.respond_to?(:failed_messages)
55
- messages = exception.failed_messages
56
- messages.group_by(&:topic).each do |topic, batch|
57
- producer = Deimos::Producer.descendants.find { |c| c.topic == topic }
58
- next if batch.empty? || !producer
59
-
60
- decoder = Deimos.schema_backend(schema: producer.config[:schema],
61
- namespace: producer.config[:namespace])
62
- payloads = batch.map { |m| decoder.decode(m.value) }
63
-
64
- Deimos.config.metrics&.increment(
65
- 'publish_error',
66
- tags: %W(topic:#{topic}),
67
- by: payloads.size
68
- )
69
- Deimos.instrument(
70
- 'produce_error',
71
- producer: producer,
72
- topic: topic,
73
- exception_object: exception,
74
- payloads: payloads
75
- )
76
- end
81
+ handle_exception_with_messages(exception)
77
82
  else
78
83
  Deimos.config.metrics&.increment(
79
84
  'publish_error',
@@ -105,6 +105,25 @@ module Deimos
105
105
  raise Deimos::MissingImplementationError
106
106
  end
107
107
 
108
+ # @param exception [Exception]
109
+ # @param batch [Array<ActiveRecord::Base>]
110
+ # @param status [PollStatus]
111
+ # @param span [Object]
112
+ # @return [Boolean]
113
+ def handle_message_too_large(exception, batch, status, span)
114
+ Deimos.config.logger.error("Error publishing through DB Poller: #{exception.message}")
115
+ if @config.skip_too_large_messages
116
+ Deimos.config.logger.error("Skipping messages #{batch.map(&:id).join(', ')} since they are too large")
117
+ Deimos.config.tracer&.set_error(span, exception)
118
+ status.batches_errored += 1
119
+ true
120
+ else # do the same thing as regular Kafka::Error
121
+ sleep(0.5)
122
+ false
123
+ end
124
+ end
125
+
126
+ # rubocop:disable Metrics/AbcSize
108
127
  # @param batch [Array<ActiveRecord::Base>]
109
128
  # @param status [PollStatus]
110
129
  # @return [Boolean]
@@ -118,6 +137,9 @@ module Deimos
118
137
  process_batch(batch)
119
138
  Deimos.config.tracer&.finish(span)
120
139
  status.batches_processed += 1
140
+ rescue Kafka::BufferOverflow, Kafka::MessageSizeTooLarge,
141
+ Kafka::RecordListTooLarge => e
142
+ retry unless handle_message_too_large(e, batch, status, span)
121
143
  rescue Kafka::Error => e # keep trying till it fixes itself
122
144
  Deimos.config.logger.error("Error publishing through DB Poller: #{e.message}")
123
145
  sleep(0.5)
@@ -139,6 +161,7 @@ module Deimos
139
161
  end
140
162
  true
141
163
  end
164
+ # rubocop:enable Metrics/AbcSize
142
165
 
143
166
  # Publish batch using the configured producers
144
167
  # @param batch [Array<ActiveRecord::Base>]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Deimos
4
- VERSION = '1.23.2'
4
+ VERSION = '1.23.3'
5
5
  end
@@ -191,6 +191,48 @@ each_db_config(Deimos::Utils::DbPoller::Base) do
191
191
  expect(Deimos.config.tracer).to have_received(:finish).with('a span')
192
192
  end
193
193
 
194
+ context 'with skip_too_large_messages on' do
195
+ before(:each) { config.skip_too_large_messages = true }
196
+
197
+ it 'should skip and move on' do
198
+ error = Kafka::MessageSizeTooLarge.new('OH NOES')
199
+ allow(poller).to receive(:sleep)
200
+ allow(poller).to receive(:process_batch) do
201
+ raise error
202
+ end
203
+ poller.retrieve_poll_info
204
+ poller.process_batch_with_span(widgets, status)
205
+ expect(poller).not_to have_received(:sleep)
206
+ expect(Deimos.config.tracer).to have_received(:set_error).with('a span', error)
207
+ expect(status.batches_errored).to eq(1)
208
+ expect(status.batches_processed).to eq(0)
209
+ expect(status.messages_processed).to eq(3)
210
+
211
+ end
212
+ end
213
+
214
+ context 'with skip_too_large_messages off' do
215
+ it 'should retry forever' do
216
+ called_once = false
217
+ allow(poller).to receive(:sleep)
218
+ allow(poller).to receive(:process_batch) do
219
+ unless called_once
220
+ called_once = true
221
+ raise Kafka::MessageSizeTooLarge, 'OH NOES'
222
+ end
223
+ end
224
+ poller.retrieve_poll_info
225
+ poller.process_batch_with_span(widgets, status)
226
+ expect(poller).to have_received(:sleep).once.with(0.5)
227
+ expect(Deimos.config.tracer).to have_received(:finish).with('a span')
228
+ expect(status.batches_errored).to eq(0)
229
+ expect(status.batches_processed).to eq(1)
230
+ expect(status.messages_processed).to eq(3)
231
+
232
+ end
233
+
234
+ end
235
+
194
236
  it 'should retry on Kafka error' do
195
237
  called_once = false
196
238
  allow(poller).to receive(:sleep)
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.23.2
4
+ version: 1.23.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Orner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-22 00:00:00.000000000 Z
11
+ date: 2024-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro_turf