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.
@@ -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
- "standard" => ConsumerGroupProtocol.new(topics: ["test-messages"]),
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[decoder.array { [decoder.string, decoder.bytes] }],
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
@@ -34,7 +34,7 @@ module Kafka
34
34
  #
35
35
  class MetadataResponse
36
36
  class PartitionMetadata
37
- attr_reader :partition_id, :leader
37
+ attr_reader :partition_id, :leader, :replicas
38
38
 
39
39
  attr_reader :partition_error_code
40
40
 
@@ -12,8 +12,10 @@ module Kafka
12
12
  OFFSET_FETCH_API
13
13
  end
14
14
 
15
+ # setting topics to nil fetches all offsets for a consumer group
16
+ # and that feature is only available in API version 2+
15
17
  def api_version
16
- 1
18
+ @topics.nil? ? 2 : 1
17
19
  end
18
20
 
19
21
  def response_class
@@ -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 initialize(cluster:)
11
- @cluster = cluster
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 members [Array<String>] member ids
17
- # @param topics [Array<String>] topics
18
- # @return [Hash<String, Protocol::MemberAssignment>] a hash mapping member
19
- # ids to assignments.
20
- def assign(members:, topics:)
21
- group_assignment = {}
22
-
23
- members.each do |member_id|
24
- group_assignment[member_id] = Protocol::MemberAssignment.new
25
- end
26
-
27
- topic_partitions = topics.flat_map do |topic|
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
- group_assignment
49
- rescue Kafka::LeaderNotAvailable
50
- sleep 1
51
- retry
28
+ partitions_per_member
52
29
  end
53
30
  end
54
31
  end
@@ -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
@@ -1,6 +1,7 @@
1
1
  # Basic implementation of a tagged logger that matches the API of
2
2
  # ActiveSupport::TaggedLogging.
3
3
 
4
+ require 'delegate'
4
5
  require 'logger'
5
6
 
6
7
  module Kafka
@@ -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
- raise 'Transaction is not valid to abort'
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kafka
4
- VERSION = "0.7.10"
4
+ VERSION = "1.3.0"
5
5
  end
@@ -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 License Version 2.0"
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", ">= 3.0.0", "< 5.0.0"
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: 0.7.10
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: 2019-08-07 00:00:00.000000000 Z
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: 3.0.0
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: 3.0.0
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: '0'
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: '0'
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 License Version 2.0
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
- rubyforge_project:
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.