ruby-kafka 0.7.10 → 1.3.0

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.
@@ -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.