deimos-ruby 1.23.2 → 1.23.3

Sign up to get free protection for your applications and to get access to all the features.
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