deimos-ruby 1.0.0.pre.beta25 → 1.0.0.pre.beta26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -2
- data/Gemfile.lock +1 -1
- data/README.md +10 -1
- data/lib/deimos/backends/kafka.rb +6 -0
- data/lib/deimos/backends/kafka_async.rb +6 -0
- data/lib/deimos/kafka_message.rb +23 -0
- data/lib/deimos/utils/db_producer.rb +27 -21
- data/lib/deimos/version.rb +1 -1
- data/lib/deimos.rb +3 -3
- data/spec/producer_spec.rb +9 -0
- data/spec/utils/db_producer_spec.rb +25 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9dbc69d5cb3ef5b93c1d926443dc2be92e295329f49edd0dec7a9e812a4e7a5
|
4
|
+
data.tar.gz: e336c6f5faf5f95c86e4d243ad0c537ba57f6db755097c83195b90bf41a1415e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57fea10ed43861b17d8fd31ba1a5d322e12db96ec7de3fff6ea28e314efe10686bc6c7fd0da2f11bdf2bfa8c7510a60bfa17c9bd836a32e3e3ed5e190faa9050
|
7
|
+
data.tar.gz: 3ffd651469987c6a337decd275c78171870ab604599f4c7ca0347ebd8e9493b8fcda7ee4b3fb0012b0cdfbc13ceb7bdd2af51392707012d4559fed05842d7239
|
data/CHANGELOG.md
CHANGED
@@ -7,10 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## UNRELEASED
|
9
9
|
|
10
|
-
## 1.0.0-
|
10
|
+
## [1.0.0-beta26] - 2019-08-29
|
11
|
+
- Recover from Kafka::MessageSizeTooLarge in the DB producer.
|
12
|
+
- Shut down sync producers correctly when persistent_connections is true.
|
13
|
+
- Notify when messages fail to produce in the DB producer.
|
14
|
+
- Delete messages on failure and rely on notification.
|
15
|
+
|
16
|
+
## [1.0.0-beta25] - 2019-08-28
|
11
17
|
- Fix bug where crashing would cause producers to stay disabled
|
12
18
|
|
13
|
-
## 1.0.0-beta24 - 2019-08-26
|
19
|
+
## [1.0.0-beta24] - 2019-08-26
|
14
20
|
- Reconnect DB backend if database goes away.
|
15
21
|
- Sleep only 5 seconds between attempts instead of using exponential backoff.
|
16
22
|
- Fix for null payload being Avro-encoded.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -197,7 +197,8 @@ You can listen to these notifications e.g. as follows:
|
|
197
197
|
end
|
198
198
|
```
|
199
199
|
|
200
|
-
The following events are
|
200
|
+
The following events are produced (in addition to the ones already
|
201
|
+
produced by Phobos and RubyKafka):
|
201
202
|
|
202
203
|
* `produce_error` - sent when an error occurs when producing a message.
|
203
204
|
* producer - the class that produced the message
|
@@ -208,6 +209,14 @@ The following events are also produced:
|
|
208
209
|
* producer - the class that produced the message
|
209
210
|
* topic
|
210
211
|
* payloads - the unencoded payloads
|
212
|
+
* `db_producer.produce` - sent when the DB producer sends messages for the
|
213
|
+
DB backend. Messages that are too large will be caught with this
|
214
|
+
notification - they will be deleted from the table and this notification
|
215
|
+
will be fired with an exception object.
|
216
|
+
* topic
|
217
|
+
* exception_object
|
218
|
+
* messages - the batch of messages (in the form of `Deimos::KafkaMessage`s)
|
219
|
+
that failed - this should have only a single message in the batch.
|
211
220
|
|
212
221
|
Similarly:
|
213
222
|
```ruby
|
@@ -6,6 +6,12 @@ module Deimos
|
|
6
6
|
class Kafka < Deimos::PublishBackend
|
7
7
|
include Phobos::Producer
|
8
8
|
|
9
|
+
# Shut down the producer if necessary.
|
10
|
+
def self.shutdown_producer
|
11
|
+
producer.sync_producer_shutdown if producer.respond_to?(:sync_producer_shutdown)
|
12
|
+
producer.kafka_client&.close
|
13
|
+
end
|
14
|
+
|
9
15
|
# :nodoc:
|
10
16
|
def self.execute(producer_class:, messages:)
|
11
17
|
Deimos.instrument(
|
@@ -6,6 +6,12 @@ module Deimos
|
|
6
6
|
class KafkaAsync < Deimos::PublishBackend
|
7
7
|
include Phobos::Producer
|
8
8
|
|
9
|
+
# Shut down the producer cleanly.
|
10
|
+
def self.shutdown_producer
|
11
|
+
producer.async_producer_shutdown
|
12
|
+
producer.kafka_client&.close
|
13
|
+
end
|
14
|
+
|
9
15
|
# :nodoc:
|
10
16
|
def self.execute(producer_class:, messages:)
|
11
17
|
Deimos.instrument(
|
data/lib/deimos/kafka_message.rb
CHANGED
@@ -14,6 +14,29 @@ module Deimos
|
|
14
14
|
write_attribute(:message, mess ? mess.to_s : nil)
|
15
15
|
end
|
16
16
|
|
17
|
+
# @return [Deimos::Consumer]
|
18
|
+
def decoder
|
19
|
+
producer = Deimos::Producer.descendants.find { |c| c.topic == self.topic }
|
20
|
+
return nil unless producer
|
21
|
+
|
22
|
+
consumer = Class.new(Deimos::Consumer)
|
23
|
+
consumer.config.merge!(producer.config)
|
24
|
+
consumer
|
25
|
+
end
|
26
|
+
|
27
|
+
# Decode the message. This assumes for now that we have access to a producer
|
28
|
+
# in the codebase which can decode it.
|
29
|
+
# @param decoder [Deimos::Consumer]
|
30
|
+
# @return [Hash]
|
31
|
+
def decoded_message(decoder=self.decoder)
|
32
|
+
return { key: self.key, message: self.message } unless decoder
|
33
|
+
|
34
|
+
{
|
35
|
+
key: self.key.present? ? decoder.new.decode_key(self.key) : nil,
|
36
|
+
payload: decoder.decoder.decode(self.message)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
17
40
|
# @return [Hash]
|
18
41
|
def phobos_message
|
19
42
|
{
|
@@ -64,22 +64,17 @@ module Deimos
|
|
64
64
|
|
65
65
|
while messages.any?
|
66
66
|
@logger.debug do
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
else
|
78
|
-
messages
|
79
|
-
end
|
80
|
-
"DB producer: Topic #{topic} Producing messages: #{decoded_messages}"
|
67
|
+
decoder = messages.first.decoder
|
68
|
+
"DB producer: Topic #{topic} Producing messages: #{messages.map { |m| m.decoded_message(decoder) }}"
|
69
|
+
end
|
70
|
+
Deimos.instrument('db_producer.produce', topic: topic, messages: messages) do
|
71
|
+
begin
|
72
|
+
produce_messages(messages.map(&:phobos_message))
|
73
|
+
rescue Kafka::BufferOverflow, Kafka::MessageSizeTooLarge, Kafka::RecordListTooLarge
|
74
|
+
messages.each(&:delete)
|
75
|
+
raise
|
76
|
+
end
|
81
77
|
end
|
82
|
-
produce_messages(messages.map(&:phobos_message))
|
83
78
|
messages.first.class.where(id: messages.map(&:id)).delete_all
|
84
79
|
break if messages.size < BATCH_SIZE
|
85
80
|
|
@@ -105,6 +100,15 @@ module Deimos
|
|
105
100
|
Deimos.config.metrics&.gauge('pending_db_messages_max_wait', time_diff)
|
106
101
|
end
|
107
102
|
|
103
|
+
# Shut down the sync producer if we have to. Phobos will automatically
|
104
|
+
# create a new one. We should call this if the producer can be in a bad
|
105
|
+
# state and e.g. we need to clear the buffer.
|
106
|
+
def shutdown_producer
|
107
|
+
if self.class.producer.respond_to?(:sync_producer_shutdown) # Phobos 1.8.3
|
108
|
+
self.class.producer.sync_producer_shutdown
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
108
112
|
# @param batch [Array<Hash>]
|
109
113
|
def produce_messages(batch)
|
110
114
|
batch_size = batch.size
|
@@ -119,18 +123,20 @@ module Deimos
|
|
119
123
|
)
|
120
124
|
@logger.info("Sent #{group.size} messages to #{@current_topic}")
|
121
125
|
end
|
122
|
-
rescue Kafka::BufferOverflow
|
123
|
-
|
126
|
+
rescue Kafka::BufferOverflow, Kafka::MessageSizeTooLarge,
|
127
|
+
Kafka::RecordListTooLarge => e
|
128
|
+
if batch_size == 1
|
129
|
+
shutdown_producer
|
130
|
+
raise
|
131
|
+
end
|
124
132
|
|
125
|
-
@logger.error("
|
133
|
+
@logger.error("Got error #{e.class.name} when publishing #{batch.size} in groups of #{batch_size}, retrying...")
|
126
134
|
if batch_size < 10
|
127
135
|
batch_size = 1
|
128
136
|
else
|
129
137
|
batch_size /= 10
|
130
138
|
end
|
131
|
-
|
132
|
-
self.class.producer.sync_producer_shutdown
|
133
|
-
end
|
139
|
+
shutdown_producer
|
134
140
|
retry
|
135
141
|
end
|
136
142
|
end
|
data/lib/deimos/version.rb
CHANGED
data/lib/deimos.rb
CHANGED
@@ -124,11 +124,11 @@ end
|
|
124
124
|
|
125
125
|
at_exit do
|
126
126
|
begin
|
127
|
-
Deimos::Backends::KafkaAsync.
|
128
|
-
Deimos::Backends::
|
127
|
+
Deimos::Backends::KafkaAsync.shutdown_producer
|
128
|
+
Deimos::Backends::Kafka.shutdown_producer
|
129
129
|
rescue StandardError => e
|
130
130
|
Deimos.config.logger.error(
|
131
|
-
"Error closing
|
131
|
+
"Error closing producer on shutdown: #{e.message} #{e.backtrace.join("\n")}"
|
132
132
|
)
|
133
133
|
end
|
134
134
|
end
|
data/spec/producer_spec.rb
CHANGED
@@ -148,6 +148,15 @@ module ProducerTest
|
|
148
148
|
expect(MyProducer.topic).to have_sent(anything)
|
149
149
|
end
|
150
150
|
|
151
|
+
it 'should send messages after a crash' do
|
152
|
+
expect {
|
153
|
+
Deimos.disable_producers do
|
154
|
+
raise 'OH NOES'
|
155
|
+
end
|
156
|
+
} .to raise_error('OH NOES')
|
157
|
+
expect(Deimos).not_to be_producers_disabled
|
158
|
+
end
|
159
|
+
|
151
160
|
it 'should produce to a prefixed topic' do
|
152
161
|
Deimos.configure { |c| c.producer_topic_prefix = 'prefix.' }
|
153
162
|
payload = { 'test_id' => 'foo', 'some_int' => 123 }
|
@@ -176,6 +176,31 @@ each_db_config(Deimos::Utils::DbProducer) do
|
|
176
176
|
producer.process_topic('my-topic')
|
177
177
|
end
|
178
178
|
|
179
|
+
it 'should notify on error' do
|
180
|
+
messages = (1..4).map do |i|
|
181
|
+
Deimos::KafkaMessage.create!(
|
182
|
+
id: i,
|
183
|
+
topic: 'my-topic',
|
184
|
+
message: "mess#{i}",
|
185
|
+
partition_key: "key#{i}"
|
186
|
+
)
|
187
|
+
end
|
188
|
+
|
189
|
+
expect(Deimos::KafkaTopicInfo).to receive(:lock).
|
190
|
+
with('my-topic', 'abc').and_return(true)
|
191
|
+
expect(producer).to receive(:produce_messages).and_raise('OH NOES')
|
192
|
+
expect(producer).to receive(:retrieve_messages).and_return(messages)
|
193
|
+
expect(Deimos::KafkaTopicInfo).to receive(:register_error)
|
194
|
+
|
195
|
+
expect(Deimos::KafkaMessage.count).to eq(4)
|
196
|
+
Deimos.subscribe('db_producer.produce') do |event|
|
197
|
+
expect(event.payload[:exception_object].message).to eq('OH NOES')
|
198
|
+
expect(event.payload[:messages]).to eq(messages)
|
199
|
+
end
|
200
|
+
producer.process_topic('my-topic')
|
201
|
+
expect(Deimos::KafkaMessage.count).to eq(0)
|
202
|
+
end
|
203
|
+
|
179
204
|
end
|
180
205
|
|
181
206
|
example 'Full integration test' do
|
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.0.0.pre.
|
4
|
+
version: 1.0.0.pre.beta26
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Orner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-08-
|
11
|
+
date: 2019-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro-patches
|