ruby-kafka 0.7.10 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +99 -0
- data/.github/workflows/stale.yml +19 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +27 -0
- data/README.md +125 -0
- data/lib/kafka/async_producer.rb +24 -12
- data/lib/kafka/client.rb +72 -4
- data/lib/kafka/cluster.rb +52 -0
- data/lib/kafka/connection.rb +3 -0
- data/lib/kafka/consumer.rb +61 -11
- data/lib/kafka/consumer_group.rb +23 -5
- data/lib/kafka/consumer_group/assignor.rb +63 -0
- data/lib/kafka/datadog.rb +20 -13
- data/lib/kafka/fetcher.rb +5 -2
- data/lib/kafka/interceptors.rb +33 -0
- data/lib/kafka/offset_manager.rb +12 -1
- data/lib/kafka/partitioner.rb +1 -1
- data/lib/kafka/producer.rb +13 -5
- data/lib/kafka/prometheus.rb +78 -79
- data/lib/kafka/protocol/join_group_request.rb +8 -2
- data/lib/kafka/protocol/join_group_response.rb +9 -1
- data/lib/kafka/protocol/metadata_response.rb +1 -1
- data/lib/kafka/protocol/offset_fetch_request.rb +3 -1
- data/lib/kafka/round_robin_assignment_strategy.rb +15 -38
- data/lib/kafka/ssl_context.rb +4 -3
- data/lib/kafka/tagged_logger.rb +1 -0
- data/lib/kafka/transaction_manager.rb +13 -8
- data/lib/kafka/version.rb +1 -1
- data/ruby-kafka.gemspec +4 -4
- metadata +21 -13
@@ -7,13 +7,14 @@ module Kafka
|
|
7
7
|
class JoinGroupRequest
|
8
8
|
PROTOCOL_TYPE = "consumer"
|
9
9
|
|
10
|
-
def initialize(group_id:, session_timeout:, member_id:, topics: [])
|
10
|
+
def initialize(group_id:, session_timeout:, rebalance_timeout:, member_id:, topics: [], protocol_name:, user_data: nil)
|
11
11
|
@group_id = group_id
|
12
12
|
@session_timeout = session_timeout * 1000 # Kafka wants ms.
|
13
|
+
@rebalance_timeout = rebalance_timeout * 1000 # Kafka wants ms.
|
13
14
|
@member_id = member_id || ""
|
14
15
|
@protocol_type = PROTOCOL_TYPE
|
15
16
|
@group_protocols = {
|
16
|
-
|
17
|
+
protocol_name => ConsumerGroupProtocol.new(topics: topics, user_data: user_data),
|
17
18
|
}
|
18
19
|
end
|
19
20
|
|
@@ -21,6 +22,10 @@ module Kafka
|
|
21
22
|
JOIN_GROUP_API
|
22
23
|
end
|
23
24
|
|
25
|
+
def api_version
|
26
|
+
1
|
27
|
+
end
|
28
|
+
|
24
29
|
def response_class
|
25
30
|
JoinGroupResponse
|
26
31
|
end
|
@@ -28,6 +33,7 @@ module Kafka
|
|
28
33
|
def encode(encoder)
|
29
34
|
encoder.write_string(@group_id)
|
30
35
|
encoder.write_int32(@session_timeout)
|
36
|
+
encoder.write_int32(@rebalance_timeout)
|
31
37
|
encoder.write_string(@member_id)
|
32
38
|
encoder.write_string(@protocol_type)
|
33
39
|
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module Kafka
|
4
4
|
module Protocol
|
5
5
|
class JoinGroupResponse
|
6
|
+
Metadata = Struct.new(:version, :topics, :user_data)
|
7
|
+
|
6
8
|
attr_reader :error_code
|
7
9
|
|
8
10
|
attr_reader :generation_id, :group_protocol
|
@@ -25,7 +27,13 @@ module Kafka
|
|
25
27
|
group_protocol: decoder.string,
|
26
28
|
leader_id: decoder.string,
|
27
29
|
member_id: decoder.string,
|
28
|
-
members: Hash[
|
30
|
+
members: Hash[
|
31
|
+
decoder.array do
|
32
|
+
member_id = decoder.string
|
33
|
+
d = Decoder.from_string(decoder.bytes)
|
34
|
+
[member_id, Metadata.new(d.int16, d.array { d.string }, d.bytes)]
|
35
|
+
end
|
36
|
+
],
|
29
37
|
)
|
30
38
|
end
|
31
39
|
end
|
@@ -1,54 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "kafka/protocol/member_assignment"
|
4
|
-
|
5
3
|
module Kafka
|
6
4
|
|
7
5
|
# A consumer group partition assignment strategy that assigns partitions to
|
8
6
|
# consumers in a round-robin fashion.
|
9
7
|
class RoundRobinAssignmentStrategy
|
10
|
-
def
|
11
|
-
|
8
|
+
def protocol_name
|
9
|
+
"roundrobin"
|
12
10
|
end
|
13
11
|
|
14
12
|
# Assign the topic partitions to the group members.
|
15
13
|
#
|
16
|
-
# @param
|
17
|
-
# @param
|
18
|
-
#
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
begin
|
29
|
-
partitions = @cluster.partitions_for(topic).map(&:partition_id)
|
30
|
-
rescue UnknownTopicOrPartition
|
31
|
-
raise UnknownTopicOrPartition, "unknown topic #{topic}"
|
32
|
-
end
|
33
|
-
Array.new(partitions.count) { topic }.zip(partitions)
|
34
|
-
end
|
35
|
-
|
36
|
-
partitions_per_member = topic_partitions.group_by.with_index do |_, index|
|
37
|
-
index % members.count
|
38
|
-
end.values
|
39
|
-
|
40
|
-
members.zip(partitions_per_member).each do |member_id, member_partitions|
|
41
|
-
unless member_partitions.nil?
|
42
|
-
member_partitions.each do |topic, partition|
|
43
|
-
group_assignment[member_id].assign(topic, [partition])
|
44
|
-
end
|
45
|
-
end
|
14
|
+
# @param cluster [Kafka::Cluster]
|
15
|
+
# @param members [Hash<String, Kafka::Protocol::JoinGroupResponse::Metadata>] a hash
|
16
|
+
# mapping member ids to metadata
|
17
|
+
# @param partitions [Array<Kafka::ConsumerGroup::Assignor::Partition>] a list of
|
18
|
+
# partitions the consumer group processes
|
19
|
+
# @return [Hash<String, Array<Kafka::ConsumerGroup::Assignor::Partition>] a hash
|
20
|
+
# mapping member ids to partitions.
|
21
|
+
def call(cluster:, members:, partitions:)
|
22
|
+
member_ids = members.keys
|
23
|
+
partitions_per_member = Hash.new {|h, k| h[k] = [] }
|
24
|
+
partitions.each_with_index do |partition, index|
|
25
|
+
partitions_per_member[member_ids[index % member_ids.count]] << partition
|
46
26
|
end
|
47
27
|
|
48
|
-
|
49
|
-
rescue Kafka::LeaderNotAvailable
|
50
|
-
sleep 1
|
51
|
-
retry
|
28
|
+
partitions_per_member
|
52
29
|
end
|
53
30
|
end
|
54
31
|
end
|
data/lib/kafka/ssl_context.rb
CHANGED
@@ -54,11 +54,12 @@ module Kafka
|
|
54
54
|
store.set_default_paths
|
55
55
|
end
|
56
56
|
ssl_context.cert_store = store
|
57
|
-
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
58
|
-
# Verify certificate hostname if supported (ruby >= 2.4.0)
|
59
|
-
ssl_context.verify_hostname = verify_hostname if ssl_context.respond_to?(:verify_hostname=)
|
60
57
|
end
|
61
58
|
|
59
|
+
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
60
|
+
# Verify certificate hostname if supported (ruby >= 2.4.0)
|
61
|
+
ssl_context.verify_hostname = verify_hostname if ssl_context.respond_to?(:verify_hostname=)
|
62
|
+
|
62
63
|
ssl_context
|
63
64
|
end
|
64
65
|
end
|
data/lib/kafka/tagged_logger.rb
CHANGED
@@ -95,7 +95,7 @@ module Kafka
|
|
95
95
|
force_transactional!
|
96
96
|
|
97
97
|
if @transaction_state.uninitialized?
|
98
|
-
raise 'Transaction is uninitialized'
|
98
|
+
raise Kafka::InvalidTxnStateError, 'Transaction is uninitialized'
|
99
99
|
end
|
100
100
|
|
101
101
|
# Extract newly created partitions
|
@@ -138,8 +138,8 @@ module Kafka
|
|
138
138
|
|
139
139
|
def begin_transaction
|
140
140
|
force_transactional!
|
141
|
-
raise 'Transaction has already started' if @transaction_state.in_transaction?
|
142
|
-
raise 'Transaction is not ready' unless @transaction_state.ready?
|
141
|
+
raise Kafka::InvalidTxnStateError, 'Transaction has already started' if @transaction_state.in_transaction?
|
142
|
+
raise Kafka::InvalidTxnStateError, 'Transaction is not ready' unless @transaction_state.ready?
|
143
143
|
@transaction_state.transition_to!(TransactionStateMachine::IN_TRANSACTION)
|
144
144
|
|
145
145
|
@logger.info "Begin transaction #{@transactional_id}, Producer ID: #{@producer_id} (Epoch #{@producer_epoch})"
|
@@ -159,7 +159,7 @@ module Kafka
|
|
159
159
|
end
|
160
160
|
|
161
161
|
unless @transaction_state.in_transaction?
|
162
|
-
raise 'Transaction is not valid to commit'
|
162
|
+
raise Kafka::InvalidTxnStateError, 'Transaction is not valid to commit'
|
163
163
|
end
|
164
164
|
|
165
165
|
@transaction_state.transition_to!(TransactionStateMachine::COMMITTING_TRANSACTION)
|
@@ -192,7 +192,8 @@ module Kafka
|
|
192
192
|
end
|
193
193
|
|
194
194
|
unless @transaction_state.in_transaction?
|
195
|
-
|
195
|
+
@logger.warn('Aborting transaction that was never opened on brokers')
|
196
|
+
return
|
196
197
|
end
|
197
198
|
|
198
199
|
@transaction_state.transition_to!(TransactionStateMachine::ABORTING_TRANSACTION)
|
@@ -221,7 +222,7 @@ module Kafka
|
|
221
222
|
force_transactional!
|
222
223
|
|
223
224
|
unless @transaction_state.in_transaction?
|
224
|
-
raise 'Transaction is not valid to send offsets'
|
225
|
+
raise Kafka::InvalidTxnStateError, 'Transaction is not valid to send offsets'
|
225
226
|
end
|
226
227
|
|
227
228
|
add_response = transaction_coordinator.add_offsets_to_txn(
|
@@ -250,6 +251,10 @@ module Kafka
|
|
250
251
|
@transaction_state.error?
|
251
252
|
end
|
252
253
|
|
254
|
+
def ready?
|
255
|
+
@transaction_state.ready?
|
256
|
+
end
|
257
|
+
|
253
258
|
def close
|
254
259
|
if in_transaction?
|
255
260
|
@logger.warn("Aborting pending transaction ...")
|
@@ -264,11 +269,11 @@ module Kafka
|
|
264
269
|
|
265
270
|
def force_transactional!
|
266
271
|
unless transactional?
|
267
|
-
raise 'Please turn on transactional mode to use transaction'
|
272
|
+
raise Kafka::InvalidTxnStateError, 'Please turn on transactional mode to use transaction'
|
268
273
|
end
|
269
274
|
|
270
275
|
if @transactional_id.nil? || @transactional_id.empty?
|
271
|
-
raise 'Please provide a transaction_id to use transactional mode'
|
276
|
+
raise Kafka::InvalidTxnStateError, 'Please provide a transaction_id to use transactional mode'
|
272
277
|
end
|
273
278
|
end
|
274
279
|
|
data/lib/kafka/version.rb
CHANGED
data/ruby-kafka.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
DESC
|
19
19
|
|
20
20
|
spec.homepage = "https://github.com/zendesk/ruby-kafka"
|
21
|
-
spec.license = "Apache
|
21
|
+
spec.license = "Apache-2.0"
|
22
22
|
|
23
23
|
spec.required_ruby_version = '>= 2.1.0'
|
24
24
|
|
@@ -36,15 +36,15 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_development_dependency "dotenv"
|
37
37
|
spec.add_development_dependency "docker-api"
|
38
38
|
spec.add_development_dependency "rspec-benchmark"
|
39
|
-
spec.add_development_dependency "activesupport"
|
39
|
+
spec.add_development_dependency "activesupport", ">= 4.0", "< 6.1"
|
40
40
|
spec.add_development_dependency "snappy"
|
41
41
|
spec.add_development_dependency "extlz4"
|
42
42
|
spec.add_development_dependency "zstd-ruby"
|
43
43
|
spec.add_development_dependency "colored"
|
44
44
|
spec.add_development_dependency "rspec_junit_formatter", "0.2.2"
|
45
|
-
spec.add_development_dependency "dogstatsd-ruby", ">=
|
45
|
+
spec.add_development_dependency "dogstatsd-ruby", ">= 4.0.0", "< 5.0.0"
|
46
46
|
spec.add_development_dependency "statsd-ruby"
|
47
|
-
spec.add_development_dependency "prometheus-client"
|
47
|
+
spec.add_development_dependency "prometheus-client", "~> 0.10.0"
|
48
48
|
spec.add_development_dependency "ruby-prof"
|
49
49
|
spec.add_development_dependency "timecop"
|
50
50
|
spec.add_development_dependency "rubocop", "~> 0.49.1"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-kafka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Schierbeck
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: digest-crc
|
@@ -128,14 +128,20 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
131
|
+
version: '4.0'
|
132
|
+
- - "<"
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '6.1'
|
132
135
|
type: :development
|
133
136
|
prerelease: false
|
134
137
|
version_requirements: !ruby/object:Gem::Requirement
|
135
138
|
requirements:
|
136
139
|
- - ">="
|
137
140
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
141
|
+
version: '4.0'
|
142
|
+
- - "<"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '6.1'
|
139
145
|
- !ruby/object:Gem::Dependency
|
140
146
|
name: snappy
|
141
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -212,7 +218,7 @@ dependencies:
|
|
212
218
|
requirements:
|
213
219
|
- - ">="
|
214
220
|
- !ruby/object:Gem::Version
|
215
|
-
version:
|
221
|
+
version: 4.0.0
|
216
222
|
- - "<"
|
217
223
|
- !ruby/object:Gem::Version
|
218
224
|
version: 5.0.0
|
@@ -222,7 +228,7 @@ dependencies:
|
|
222
228
|
requirements:
|
223
229
|
- - ">="
|
224
230
|
- !ruby/object:Gem::Version
|
225
|
-
version:
|
231
|
+
version: 4.0.0
|
226
232
|
- - "<"
|
227
233
|
- !ruby/object:Gem::Version
|
228
234
|
version: 5.0.0
|
@@ -244,16 +250,16 @@ dependencies:
|
|
244
250
|
name: prometheus-client
|
245
251
|
requirement: !ruby/object:Gem::Requirement
|
246
252
|
requirements:
|
247
|
-
- - "
|
253
|
+
- - "~>"
|
248
254
|
- !ruby/object:Gem::Version
|
249
|
-
version:
|
255
|
+
version: 0.10.0
|
250
256
|
type: :development
|
251
257
|
prerelease: false
|
252
258
|
version_requirements: !ruby/object:Gem::Requirement
|
253
259
|
requirements:
|
254
|
-
- - "
|
260
|
+
- - "~>"
|
255
261
|
- !ruby/object:Gem::Version
|
256
|
-
version:
|
262
|
+
version: 0.10.0
|
257
263
|
- !ruby/object:Gem::Dependency
|
258
264
|
name: ruby-prof
|
259
265
|
requirement: !ruby/object:Gem::Requirement
|
@@ -332,6 +338,7 @@ extensions: []
|
|
332
338
|
extra_rdoc_files: []
|
333
339
|
files:
|
334
340
|
- ".circleci/config.yml"
|
341
|
+
- ".github/workflows/stale.yml"
|
335
342
|
- ".gitignore"
|
336
343
|
- ".readygo"
|
337
344
|
- ".rspec"
|
@@ -369,6 +376,7 @@ files:
|
|
369
376
|
- lib/kafka/connection_builder.rb
|
370
377
|
- lib/kafka/consumer.rb
|
371
378
|
- lib/kafka/consumer_group.rb
|
379
|
+
- lib/kafka/consumer_group/assignor.rb
|
372
380
|
- lib/kafka/datadog.rb
|
373
381
|
- lib/kafka/fetch_operation.rb
|
374
382
|
- lib/kafka/fetched_batch.rb
|
@@ -379,6 +387,7 @@ files:
|
|
379
387
|
- lib/kafka/gzip_codec.rb
|
380
388
|
- lib/kafka/heartbeat.rb
|
381
389
|
- lib/kafka/instrumenter.rb
|
390
|
+
- lib/kafka/interceptors.rb
|
382
391
|
- lib/kafka/lz4_codec.rb
|
383
392
|
- lib/kafka/message_buffer.rb
|
384
393
|
- lib/kafka/offset_manager.rb
|
@@ -469,7 +478,7 @@ files:
|
|
469
478
|
- ruby-kafka.gemspec
|
470
479
|
homepage: https://github.com/zendesk/ruby-kafka
|
471
480
|
licenses:
|
472
|
-
- Apache
|
481
|
+
- Apache-2.0
|
473
482
|
metadata: {}
|
474
483
|
post_install_message:
|
475
484
|
rdoc_options: []
|
@@ -486,8 +495,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
486
495
|
- !ruby/object:Gem::Version
|
487
496
|
version: '0'
|
488
497
|
requirements: []
|
489
|
-
|
490
|
-
rubygems_version: 2.7.6
|
498
|
+
rubygems_version: 3.1.2
|
491
499
|
signing_key:
|
492
500
|
specification_version: 4
|
493
501
|
summary: A client library for the Kafka distributed commit log.
|