kafka-consumer 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/.travis.yml +10 -0
- data/README.md +9 -1
- data/Rakefile +2 -10
- data/kafka-consumer.gemspec +1 -1
- data/lib/kafka-consumer.rb +1 -0
- data/lib/kafka/consumer.rb +11 -16
- data/lib/kafka/consumer/version.rb +1 -1
- data/test/test_helper.rb +0 -44
- metadata +8 -24
- data/bin/kazoo +0 -14
- data/lib/kazoo.rb +0 -19
- data/lib/kazoo/broker.rb +0 -68
- data/lib/kazoo/cli.rb +0 -78
- data/lib/kazoo/cluster.rb +0 -78
- data/lib/kazoo/consumergroup.rb +0 -215
- data/lib/kazoo/partition.rb +0 -62
- data/lib/kazoo/topic.rb +0 -46
- data/lib/kazoo/version.rb +0 -3
- data/test/broker_test.rb +0 -45
- data/test/cluster_test.rb +0 -16
- data/test/partition_test.rb +0 -25
- data/test/topic_test.rb +0 -40
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd211d48c462dd372ab59425ef6f36b79460abd0
|
|
4
|
+
data.tar.gz: b13cb4c3d7fcbba2c6c7703eb6ea4e6d72fc030d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 48d39d21d7370f509b644667ae428c0d8c7ef27883d336ef98e102e4efb2f7f75909959acff27e8b75cfba56b681a1df5f2337f3031e4e6fdfd1bd7ae094536c
|
|
7
|
+
data.tar.gz: 2de3c13aa95faeb7ed27d7a558ac03c22f5098fb47d28f76125d276608a55d4b6c9e6c1bdba8030601e8bd42f4df43f8a956b24b6690622299f4237dd0db8b74
|
data/.travis.yml
ADDED
data/README.md
CHANGED
|
@@ -11,7 +11,7 @@ instance at a time. It uses Zookeeper watches to be notified of new consumer ins
|
|
|
11
11
|
online or going offline, which will trigger a redistribition of all the partitions that are consumed.
|
|
12
12
|
|
|
13
13
|
Periodically, it will commit the last processed offset of every partition to Zookeeper. Whenever a
|
|
14
|
-
new consumer starts, it will resume
|
|
14
|
+
new consumer starts, it will resume consuming every partition at the last committed offset. This implements
|
|
15
15
|
an **at least once guarantee**, so it is possible that you end up consuming the same message more than once.
|
|
16
16
|
It's your responsibility to deal with this if that is a problem for you, e.g. by using idempotent operations.
|
|
17
17
|
|
|
@@ -34,6 +34,14 @@ consumer.each do |message|
|
|
|
34
34
|
end
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
## Notes
|
|
38
|
+
|
|
39
|
+
- It will spawn a manager thread and two threads per partition. However, your code
|
|
40
|
+
doesn't have to be thread-safe because every message is yielded to `each`
|
|
41
|
+
sequentially using a mutex.
|
|
42
|
+
- On my Macbook Pro, I can consume around ~10,000 messages per second from a
|
|
43
|
+
topic with 64 partitions on a production Kafka cluster.
|
|
44
|
+
|
|
37
45
|
## Contributing
|
|
38
46
|
|
|
39
47
|
1. Fork it ( https://github.com/wvanbergen/kafka-consumer/fork )
|
data/Rakefile
CHANGED
|
@@ -30,14 +30,6 @@ namespace :kafka do
|
|
|
30
30
|
puts
|
|
31
31
|
puts "%d messages consumed in %0.3fs (%0.3f msg/s)" % [counter, duration, counter.to_f / duration]
|
|
32
32
|
end
|
|
33
|
-
|
|
34
|
-
namespace :consumer do
|
|
35
|
-
task :reset do
|
|
36
|
-
zookeeper = ENV["ZOOKEEPER"] or raise "Specify the ZOOKEEPER connection string."
|
|
37
|
-
name = ENV["NAME"] or raise "Specify NAME to name the consumergroup."
|
|
38
|
-
|
|
39
|
-
consumer = Kafka::Consumer.new(name, [], zookeeper: zookeeper)
|
|
40
|
-
consumer.group.reset_offsets
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
33
|
end
|
|
34
|
+
|
|
35
|
+
task default: :test
|
data/kafka-consumer.gemspec
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'kafka/consumer'
|
data/lib/kafka/consumer.rb
CHANGED
|
@@ -9,8 +9,6 @@ require "kafka/consumer/version"
|
|
|
9
9
|
|
|
10
10
|
module Kafka
|
|
11
11
|
class Consumer
|
|
12
|
-
BACKPRESSURE_MESSAGE_LIMIT = 1000
|
|
13
|
-
|
|
14
12
|
include Enumerable
|
|
15
13
|
|
|
16
14
|
attr_reader :subscription,
|
|
@@ -18,17 +16,19 @@ module Kafka
|
|
|
18
16
|
:max_wait_ms, :initial_offset,
|
|
19
17
|
:logger
|
|
20
18
|
|
|
21
|
-
def initialize(name, subscription, zookeeper:
|
|
22
|
-
|
|
19
|
+
def initialize(name, subscription, zookeeper: nil, max_wait_ms: 200, initial_offset: :latest_offset, logger: nil)
|
|
20
|
+
raise ArgumentError, "The consumer's name cannot be empty" if name.nil? || name.empty?
|
|
21
|
+
raise ArgumentError, "You have to specify a zookeeper connection string" if zookeeper.nil? || zookeeper.empty?
|
|
22
|
+
|
|
23
|
+
@name = name
|
|
23
24
|
@max_wait_ms, @initial_offset = max_wait_ms, initial_offset
|
|
24
25
|
@logger = logger || Logger.new($stdout)
|
|
25
26
|
|
|
26
27
|
@cluster = Kazoo::Cluster.new(zookeeper)
|
|
27
28
|
@group = Kazoo::Consumergroup.new(@cluster, name)
|
|
28
|
-
@group.create unless @group.exists?
|
|
29
29
|
|
|
30
|
-
@
|
|
31
|
-
@instance.
|
|
30
|
+
@group.create unless @group.exists?
|
|
31
|
+
@instance = @group.instantiate(subscription: Kazoo::Subscription.build(subscription)).register
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def name
|
|
@@ -39,15 +39,12 @@ module Kafka
|
|
|
39
39
|
instance.id
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
def
|
|
43
|
-
|
|
44
|
-
topic_names = Array(subscription)
|
|
45
|
-
topic_names.map { |topic_name| cluster.topics.fetch(topic_name) }
|
|
46
|
-
end
|
|
42
|
+
def subscription
|
|
43
|
+
instance.subscription
|
|
47
44
|
end
|
|
48
45
|
|
|
49
46
|
def partitions
|
|
50
|
-
|
|
47
|
+
subscription.partitions(@cluster).sort_by { |partition| [partition.preferred_leader.id, partition.topic.name, partition.id] }
|
|
51
48
|
end
|
|
52
49
|
|
|
53
50
|
def interrupt
|
|
@@ -83,9 +80,7 @@ module Kafka
|
|
|
83
80
|
mutex = Mutex.new
|
|
84
81
|
|
|
85
82
|
handler = lambda do |message|
|
|
86
|
-
mutex.synchronize
|
|
87
|
-
block.call(message)
|
|
88
|
-
end
|
|
83
|
+
mutex.synchronize { block.call(message) }
|
|
89
84
|
end
|
|
90
85
|
|
|
91
86
|
@consumer_manager = Thread.new do
|
data/test/test_helper.rb
CHANGED
|
@@ -1,48 +1,4 @@
|
|
|
1
1
|
require 'minitest/autorun'
|
|
2
2
|
require 'kafka/consumer'
|
|
3
|
-
require 'kazoo'
|
|
4
3
|
require 'mocha/mini_test'
|
|
5
4
|
require 'pp'
|
|
6
|
-
|
|
7
|
-
module MockCluster
|
|
8
|
-
def mock_cluster
|
|
9
|
-
cluster = Kazoo::Cluster.new('example.com:2181')
|
|
10
|
-
cluster.stubs(:zk).returns(mock)
|
|
11
|
-
|
|
12
|
-
cluster.stubs(:brokers).returns(
|
|
13
|
-
1 => Kazoo::Broker.new(cluster, 1, 'example.com', 9091),
|
|
14
|
-
2 => Kazoo::Broker.new(cluster, 2, 'example.com', 9092),
|
|
15
|
-
3 => Kazoo::Broker.new(cluster, 3, 'example.com', 9093),
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
cluster.stubs(:topics).returns(
|
|
19
|
-
'test.1' => topic_1 = Kazoo::Topic.new(cluster, 'test.1'),
|
|
20
|
-
'test.4' => topic_4 = Kazoo::Topic.new(cluster, 'test.4')
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
topic_1.stubs(:partitions).returns([
|
|
24
|
-
Kazoo::Partition.new(topic_1, 0, replicas: [cluster.brokers[1], cluster.brokers[2]]),
|
|
25
|
-
])
|
|
26
|
-
|
|
27
|
-
topic_4.stubs(:partitions).returns([
|
|
28
|
-
Kazoo::Partition.new(topic_4, 0, replicas: [cluster.brokers[2], cluster.brokers[1]]),
|
|
29
|
-
Kazoo::Partition.new(topic_4, 1, replicas: [cluster.brokers[2], cluster.brokers[3]]),
|
|
30
|
-
Kazoo::Partition.new(topic_4, 2, replicas: [cluster.brokers[1], cluster.brokers[3]]),
|
|
31
|
-
Kazoo::Partition.new(topic_4, 3, replicas: [cluster.brokers[3], cluster.brokers[2]]),
|
|
32
|
-
])
|
|
33
|
-
|
|
34
|
-
topic_1.partitions[0].stubs(:isr).returns([cluster.brokers[1], cluster.brokers[2]])
|
|
35
|
-
topic_4.partitions[0].stubs(:isr).returns([cluster.brokers[2], cluster.brokers[1]])
|
|
36
|
-
topic_4.partitions[1].stubs(:isr).returns([cluster.brokers[2], cluster.brokers[3]])
|
|
37
|
-
topic_4.partitions[2].stubs(:isr).returns([cluster.brokers[1], cluster.brokers[3]])
|
|
38
|
-
topic_4.partitions[3].stubs(:isr).returns([cluster.brokers[3], cluster.brokers[2]])
|
|
39
|
-
|
|
40
|
-
topic_1.partitions[0].stubs(:leader).returns(cluster.brokers[1])
|
|
41
|
-
topic_4.partitions[0].stubs(:leader).returns(cluster.brokers[2])
|
|
42
|
-
topic_4.partitions[1].stubs(:leader).returns(cluster.brokers[2])
|
|
43
|
-
topic_4.partitions[2].stubs(:leader).returns(cluster.brokers[1])
|
|
44
|
-
topic_4.partitions[3].stubs(:leader).returns(cluster.brokers[3])
|
|
45
|
-
|
|
46
|
-
return cluster
|
|
47
|
-
end
|
|
48
|
-
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kafka-consumer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Willem van Bergen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-10-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -81,53 +81,41 @@ dependencies:
|
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: 0.0.5
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: kazoo-ruby
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - ~>
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
89
|
+
version: 0.4.0
|
|
90
90
|
type: :runtime
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
94
|
- - ~>
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
96
|
+
version: 0.4.0
|
|
97
97
|
description: High-level consumer for Kafka. Implements the Zookeeper-backed consumer
|
|
98
98
|
implementation that offers offset management, load balancing and automatic failovers.
|
|
99
99
|
email:
|
|
100
100
|
- willem@vanbergen.org
|
|
101
|
-
executables:
|
|
102
|
-
- kazoo
|
|
101
|
+
executables: []
|
|
103
102
|
extensions: []
|
|
104
103
|
extra_rdoc_files: []
|
|
105
104
|
files:
|
|
106
105
|
- .gitignore
|
|
106
|
+
- .travis.yml
|
|
107
107
|
- Gemfile
|
|
108
108
|
- LICENSE.txt
|
|
109
109
|
- README.md
|
|
110
110
|
- Rakefile
|
|
111
|
-
- bin/kazoo
|
|
112
111
|
- kafka-consumer.gemspec
|
|
112
|
+
- lib/kafka-consumer.rb
|
|
113
113
|
- lib/kafka/consumer.rb
|
|
114
114
|
- lib/kafka/consumer/message.rb
|
|
115
115
|
- lib/kafka/consumer/partition_consumer.rb
|
|
116
116
|
- lib/kafka/consumer/version.rb
|
|
117
|
-
- lib/kazoo.rb
|
|
118
|
-
- lib/kazoo/broker.rb
|
|
119
|
-
- lib/kazoo/cli.rb
|
|
120
|
-
- lib/kazoo/cluster.rb
|
|
121
|
-
- lib/kazoo/consumergroup.rb
|
|
122
|
-
- lib/kazoo/partition.rb
|
|
123
|
-
- lib/kazoo/topic.rb
|
|
124
|
-
- lib/kazoo/version.rb
|
|
125
|
-
- test/broker_test.rb
|
|
126
|
-
- test/cluster_test.rb
|
|
127
117
|
- test/partition_distribution_test.rb
|
|
128
|
-
- test/partition_test.rb
|
|
129
118
|
- test/test_helper.rb
|
|
130
|
-
- test/topic_test.rb
|
|
131
119
|
homepage: https://github.com/wvanbergen/kafka-consumer
|
|
132
120
|
licenses:
|
|
133
121
|
- MIT
|
|
@@ -153,9 +141,5 @@ signing_key:
|
|
|
153
141
|
specification_version: 4
|
|
154
142
|
summary: High-level consumer for Kafka
|
|
155
143
|
test_files:
|
|
156
|
-
- test/broker_test.rb
|
|
157
|
-
- test/cluster_test.rb
|
|
158
144
|
- test/partition_distribution_test.rb
|
|
159
|
-
- test/partition_test.rb
|
|
160
145
|
- test/test_helper.rb
|
|
161
|
-
- test/topic_test.rb
|
data/bin/kazoo
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
|
3
|
-
require 'kazoo/cli'
|
|
4
|
-
|
|
5
|
-
begin
|
|
6
|
-
ENV["THOR_DEBUG"] = "1"
|
|
7
|
-
Kazoo::CLI.start(ARGV)
|
|
8
|
-
rescue Thor::UndefinedCommandError, Thor::UnknownArgumentError, Thor::AmbiguousCommandError, Thor::InvocationError => e
|
|
9
|
-
$stderr.puts(e.message)
|
|
10
|
-
exit(64)
|
|
11
|
-
rescue Thor::Error => e
|
|
12
|
-
$stderr.puts(e.message)
|
|
13
|
-
exit(1)
|
|
14
|
-
end
|
data/lib/kazoo.rb
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
require 'zookeeper'
|
|
2
|
-
require 'json'
|
|
3
|
-
require 'thread'
|
|
4
|
-
require 'socket'
|
|
5
|
-
require 'securerandom'
|
|
6
|
-
|
|
7
|
-
module Kazoo
|
|
8
|
-
Error = Class.new(StandardError)
|
|
9
|
-
ConsumerInstanceRegistrationFailed = Class.new(Kazoo::Error)
|
|
10
|
-
PartitionAlreadyClaimed = Class.new(Kazoo::Error)
|
|
11
|
-
ReleasePartitionFailure = Class.new(Kazoo::Error)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
require 'kazoo/cluster'
|
|
15
|
-
require 'kazoo/broker'
|
|
16
|
-
require 'kazoo/topic'
|
|
17
|
-
require 'kazoo/partition'
|
|
18
|
-
require 'kazoo/consumergroup'
|
|
19
|
-
require 'kazoo/version'
|
data/lib/kazoo/broker.rb
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
module Kazoo
|
|
2
|
-
class Broker
|
|
3
|
-
attr_reader :cluster, :id, :host, :port, :jmx_port
|
|
4
|
-
|
|
5
|
-
def initialize(cluster, id, host, port, jmx_port: nil)
|
|
6
|
-
@cluster = cluster
|
|
7
|
-
@id, @host, @port = id, host, port
|
|
8
|
-
@jmx_port = jmx_port
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def led_partitions
|
|
12
|
-
result, threads, mutex = [], ThreadGroup.new, Mutex.new
|
|
13
|
-
cluster.partitions.each do |partition|
|
|
14
|
-
t = Thread.new do
|
|
15
|
-
select = partition.leader == self
|
|
16
|
-
mutex.synchronize { result << partition } if select
|
|
17
|
-
end
|
|
18
|
-
threads.add(t)
|
|
19
|
-
end
|
|
20
|
-
threads.list.each(&:join)
|
|
21
|
-
result
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def replicated_partitions
|
|
25
|
-
result, threads, mutex = [], ThreadGroup.new, Mutex.new
|
|
26
|
-
cluster.partitions.each do |partition|
|
|
27
|
-
t = Thread.new do
|
|
28
|
-
select = partition.replicas.include?(self)
|
|
29
|
-
mutex.synchronize { result << partition } if select
|
|
30
|
-
end
|
|
31
|
-
threads.add(t)
|
|
32
|
-
end
|
|
33
|
-
threads.list.each(&:join)
|
|
34
|
-
result
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def critical?(replicas: 1)
|
|
38
|
-
result, threads, mutex = false, ThreadGroup.new, Mutex.new
|
|
39
|
-
replicated_partitions.each do |partition|
|
|
40
|
-
t = Thread.new do
|
|
41
|
-
isr = partition.isr.reject { |r| r == self }
|
|
42
|
-
mutex.synchronize { result = true if isr.length < replicas }
|
|
43
|
-
end
|
|
44
|
-
threads.add(t)
|
|
45
|
-
end
|
|
46
|
-
threads.list.each(&:join)
|
|
47
|
-
result
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def addr
|
|
51
|
-
"#{host}:#{port}"
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def eql?(other)
|
|
55
|
-
other.is_a?(Kazoo::Broker) && other.cluster == self.cluster && other.id == self.id
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
alias_method :==, :eql?
|
|
59
|
-
|
|
60
|
-
def hash
|
|
61
|
-
[self.cluster, self.id].hash
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def self.from_json(cluster, id, json)
|
|
65
|
-
new(cluster, id.to_i, json.fetch('host'), json.fetch('port'), jmx_port: json.fetch('jmx_port', nil))
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
data/lib/kazoo/cli.rb
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
require 'kazoo'
|
|
2
|
-
require 'thor'
|
|
3
|
-
|
|
4
|
-
module Kazoo
|
|
5
|
-
class CLI < Thor
|
|
6
|
-
class_option :zookeeper, :type => :string, :default => ENV['ZOOKEEPER']
|
|
7
|
-
|
|
8
|
-
desc "cluster", "Describes the Kafka cluster as registered in Zookeeper"
|
|
9
|
-
def cluster
|
|
10
|
-
validate_class_options!
|
|
11
|
-
|
|
12
|
-
kafka_cluster.brokers.values.sort_by(&:id).each do |broker|
|
|
13
|
-
$stdout.puts "#{broker.id}:\t#{broker.addr}\t(hosts #{broker.replicated_partitions.length} partitions, leads #{broker.led_partitions.length})"
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
desc "topics", "Lists all topics in the cluster"
|
|
18
|
-
def topics
|
|
19
|
-
validate_class_options!
|
|
20
|
-
|
|
21
|
-
kafka_cluster.topics.values.sort_by(&:name).each do |topic|
|
|
22
|
-
$stdout.puts topic.name
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
option :topic, :type => :string
|
|
27
|
-
desc "partitions", "Lists partitions"
|
|
28
|
-
def partitions
|
|
29
|
-
validate_class_options!
|
|
30
|
-
|
|
31
|
-
topics = kafka_cluster.topics.values
|
|
32
|
-
topics.select! { |t| t.name == options[:topic] } if options[:topic]
|
|
33
|
-
topics.sort_by!(&:name)
|
|
34
|
-
|
|
35
|
-
topics.each do |topic|
|
|
36
|
-
topic.partitions.each do |partition|
|
|
37
|
-
$stdout.puts "#{partition.topic.name}/#{partition.id}\tReplicas: #{partition.replicas.map(&:id).join(",")}"
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
option :replicas, :type => :numeric, :default => 1
|
|
43
|
-
desc "critical <broker>", "Determine whether a broker is critical"
|
|
44
|
-
def critical(broker_name)
|
|
45
|
-
validate_class_options!
|
|
46
|
-
|
|
47
|
-
if broker(broker_name).critical?(replicas: options[:replicas])
|
|
48
|
-
raise Thor::Error, "WARNING: broker #{broker_name} is critical and cannot be stopped safely!"
|
|
49
|
-
else
|
|
50
|
-
$stdout.puts "Broker #{broker_name} is non-critical and can be stopped safely."
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
private
|
|
56
|
-
|
|
57
|
-
def validate_class_options!
|
|
58
|
-
if options[:zookeeper].nil? || options[:zookeeper] == ''
|
|
59
|
-
raise Thor::InvocationError, "Please supply --zookeeper argument, or set the ZOOKEEPER_PEERS environment variable"
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def broker(name_or_id)
|
|
64
|
-
broker = if name_or_id =~ /\A\d+\z/
|
|
65
|
-
kafka_cluster.brokers[name_or_id.to_i]
|
|
66
|
-
else
|
|
67
|
-
kafka_cluster.brokers.values.detect { |b| b.addr == name_or_id } || cluster.brokers.values.detect { |b| b.host == name_or_id }
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
raise Thor::InvocationError, "Broker #{name_or_id.inspect} not found!" if broker.nil?
|
|
71
|
-
broker
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def kafka_cluster
|
|
75
|
-
@kafka_cluster ||= Kazoo::Cluster.new(options[:zookeeper])
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
data/lib/kazoo/cluster.rb
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
module Kazoo
|
|
2
|
-
class Cluster
|
|
3
|
-
|
|
4
|
-
attr_reader :zookeeper
|
|
5
|
-
|
|
6
|
-
def initialize(zookeeper)
|
|
7
|
-
@zookeeper = zookeeper
|
|
8
|
-
@zk_mutex, @brokers_mutex, @topics_mutex, @consumergroups_mutex = Mutex.new, Mutex.new, Mutex.new, Mutex.new
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def zk
|
|
12
|
-
@zk_mutex.synchronize do
|
|
13
|
-
@zk ||= Zookeeper.new(zookeeper)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def brokers
|
|
18
|
-
@brokers_mutex.synchronize do
|
|
19
|
-
@brokers ||= begin
|
|
20
|
-
brokers = zk.get_children(path: "/brokers/ids")
|
|
21
|
-
result, threads, mutex = {}, ThreadGroup.new, Mutex.new
|
|
22
|
-
brokers.fetch(:children).map do |id|
|
|
23
|
-
t = Thread.new do
|
|
24
|
-
broker_info = zk.get(path: "/brokers/ids/#{id}")
|
|
25
|
-
broker = Kazoo::Broker.from_json(self, id, JSON.parse(broker_info.fetch(:data)))
|
|
26
|
-
mutex.synchronize { result[id.to_i] = broker }
|
|
27
|
-
end
|
|
28
|
-
threads.add(t)
|
|
29
|
-
end
|
|
30
|
-
threads.list.each(&:join)
|
|
31
|
-
result
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def consumergroups
|
|
37
|
-
@consumergroups ||= begin
|
|
38
|
-
consumers = zk.get_children(path: "/consumers")
|
|
39
|
-
consumers.fetch(:children).map { |name| Kazoo::Consumergroup.new(self, name) }
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def topics
|
|
44
|
-
@topics_mutex.synchronize do
|
|
45
|
-
@topics ||= begin
|
|
46
|
-
topics = zk.get_children(path: "/brokers/topics")
|
|
47
|
-
result, threads, mutex = {}, ThreadGroup.new, Mutex.new
|
|
48
|
-
topics.fetch(:children).each do |name|
|
|
49
|
-
t = Thread.new do
|
|
50
|
-
topic_info = zk.get(path: "/brokers/topics/#{name}")
|
|
51
|
-
topic = Kazoo::Topic.from_json(self, name, JSON.parse(topic_info.fetch(:data)))
|
|
52
|
-
mutex.synchronize { result[name] = topic }
|
|
53
|
-
end
|
|
54
|
-
threads.add(t)
|
|
55
|
-
end
|
|
56
|
-
threads.list.each(&:join)
|
|
57
|
-
result
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def partitions
|
|
63
|
-
topics.values.flat_map(&:partitions)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def reset_metadata
|
|
67
|
-
@topics, @brokers = nil, nil
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def under_replicated?
|
|
71
|
-
partitions.any?(&:under_replicated?)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def close
|
|
75
|
-
zk.close
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
data/lib/kazoo/consumergroup.rb
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
module Kazoo
|
|
2
|
-
class Consumergroup
|
|
3
|
-
attr_reader :cluster, :name
|
|
4
|
-
|
|
5
|
-
def initialize(cluster, name)
|
|
6
|
-
@cluster, @name = cluster, name
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def create
|
|
10
|
-
cluster.zk.create(path: "/consumers/#{name}")
|
|
11
|
-
cluster.zk.create(path: "/consumers/#{name}/ids")
|
|
12
|
-
cluster.zk.create(path: "/consumers/#{name}/owners")
|
|
13
|
-
cluster.zk.create(path: "/consumers/#{name}/offsets")
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def exists?
|
|
17
|
-
stat = cluster.zk.stat(path: "/consumers/#{name}")
|
|
18
|
-
stat.fetch(:stat).exists?
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def instantiate(id: nil)
|
|
23
|
-
Instance.new(self, id: id)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def instances
|
|
27
|
-
instances = cluster.zk.get_children(path: "/consumers/#{name}/ids")
|
|
28
|
-
instances.fetch(:children).map { |id| Instance.new(self, id: id) }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def watch_instances(&block)
|
|
32
|
-
cb = Zookeeper::Callbacks::WatcherCallback.create(&block)
|
|
33
|
-
result = cluster.zk.get_children(path: "/consumers/#{name}/ids", watcher: cb)
|
|
34
|
-
|
|
35
|
-
if result.fetch(:rc) != Zookeeper::Constants::ZOK
|
|
36
|
-
raise Kazoo::Error, "Failed to watch instances. Error code result[:rc]"
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
instances = result.fetch(:children).map { |id| Instance.new(self, id: id) }
|
|
40
|
-
[instances, cb]
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def watch_partition_claim(partition, &block)
|
|
45
|
-
cb = Zookeeper::Callbacks::WatcherCallback.create(&block)
|
|
46
|
-
|
|
47
|
-
result = cluster.zk.get(path: "/consumers/#{name}/owners/#{partition.topic.name}/#{partition.id}", watcher: cb)
|
|
48
|
-
|
|
49
|
-
case result.fetch(:rc)
|
|
50
|
-
when Zookeeper::Constants::ZNONODE # Nobody is claiming this partition yet
|
|
51
|
-
[nil, nil]
|
|
52
|
-
when Zookeeper::Constants::ZOK
|
|
53
|
-
[Kazoo::Consumergroup::Instance.new(self, id: result.fetch(:data)), cb]
|
|
54
|
-
else
|
|
55
|
-
raise Kazoo::Error, "Failed set watch for partition claim of #{partition.topic.name}/#{partition.id}. Error code: #{result.fetch(:rc)}"
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def retrieve_offset(partition)
|
|
60
|
-
result = cluster.zk.get(path: "/consumers/#{name}/offsets/#{partition.topic.name}/#{partition.id}")
|
|
61
|
-
case result.fetch(:rc)
|
|
62
|
-
when Zookeeper::Constants::ZOK;
|
|
63
|
-
result.fetch(:data).to_i
|
|
64
|
-
when Zookeeper::Constants::ZNONODE;
|
|
65
|
-
nil
|
|
66
|
-
else
|
|
67
|
-
raise Kazoo::Error, "Failed to retrieve offset for partition #{partition.topic.name}/#{partition.id}. Error code: #{result.fetch(:rc)}"
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def commit_offset(partition, offset)
|
|
72
|
-
result = cluster.zk.set(path: "/consumers/#{name}/offsets/#{partition.topic.name}/#{partition.id}", data: (offset + 1).to_s)
|
|
73
|
-
if result.fetch(:rc) == Zookeeper::Constants::ZNONODE
|
|
74
|
-
result = cluster.zk.create(path: "/consumers/#{name}/offsets/#{partition.topic.name}")
|
|
75
|
-
case result.fetch(:rc)
|
|
76
|
-
when Zookeeper::Constants::ZOK, Zookeeper::Constants::ZNODEEXISTS
|
|
77
|
-
else
|
|
78
|
-
raise Kazoo::Error, "Failed to commit offset #{offset} for partition #{partition.topic.name}/#{partition.id}. Error code: #{result.fetch(:rc)}"
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
result = cluster.zk.create(path: "/consumers/#{name}/offsets/#{partition.topic.name}/#{partition.id}", data: (offset + 1).to_s)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
if result.fetch(:rc) != Zookeeper::Constants::ZOK
|
|
85
|
-
raise Kazoo::Error, "Failed to commit offset #{offset} for partition #{partition.topic.name}/#{partition.id}. Error code: #{result.fetch(:rc)}"
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def reset_offsets
|
|
90
|
-
result = cluster.zk.get_children(path: "/consumers/#{name}/offsets")
|
|
91
|
-
raise Kazoo::Error unless result.fetch(:rc) == Zookeeper::Constants::ZOK
|
|
92
|
-
|
|
93
|
-
result.fetch(:children).each do |topic|
|
|
94
|
-
result = cluster.zk.get_children(path: "/consumers/#{name}/offsets/#{topic}")
|
|
95
|
-
raise Kazoo::Error unless result.fetch(:rc) == Zookeeper::Constants::ZOK
|
|
96
|
-
|
|
97
|
-
result.fetch(:children).each do |partition|
|
|
98
|
-
cluster.zk.delete(path: "/consumers/#{name}/offsets/#{topic}/#{partition}")
|
|
99
|
-
raise Kazoo::Error unless result.fetch(:rc) == Zookeeper::Constants::ZOK
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
cluster.zk.delete(path: "/consumers/#{name}/offsets/#{topic}")
|
|
103
|
-
raise Kazoo::Error unless result.fetch(:rc) == Zookeeper::Constants::ZOK
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def inspect
|
|
108
|
-
"#<Kazoo::Consumergroup name=#{name}>"
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def eql?(other)
|
|
112
|
-
other.kind_of?(Kazoo::Consumergroup) && cluster == other.cluster && name == other.name
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
alias_method :==, :eql?
|
|
116
|
-
|
|
117
|
-
def hash
|
|
118
|
-
[cluster, name].hash
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
class Instance
|
|
122
|
-
|
|
123
|
-
def self.generate_id
|
|
124
|
-
"#{Socket.gethostname}:#{SecureRandom.uuid}"
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
attr_reader :group, :id
|
|
128
|
-
|
|
129
|
-
def initialize(group, id: nil)
|
|
130
|
-
@group = group
|
|
131
|
-
@id = id || self.class.generate_id
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def registered?
|
|
135
|
-
stat = cluster.zk.stat(path: "/consumers/#{group.name}/ids/#{id}")
|
|
136
|
-
stat.fetch(:stat).exists?
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def register(subscription)
|
|
140
|
-
result = cluster.zk.create(
|
|
141
|
-
path: "/consumers/#{group.name}/ids/#{id}",
|
|
142
|
-
ephemeral: true,
|
|
143
|
-
data: JSON.generate({
|
|
144
|
-
version: 1,
|
|
145
|
-
timestamp: Time.now.to_i,
|
|
146
|
-
pattern: "static",
|
|
147
|
-
subscription: Hash[*subscription.flat_map { |topic| [topic.name, 1] } ]
|
|
148
|
-
})
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
if result.fetch(:rc) != Zookeeper::Constants::ZOK
|
|
152
|
-
raise Kazoo::ConsumerInstanceRegistrationFailed, "Failed to register instance #{id} for consumer group #{group.name}! Error code: #{result.fetch(:rc)}"
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
subscription.each do |topic|
|
|
156
|
-
stat = cluster.zk.stat(path: "/consumers/#{group.name}/owners/#{topic.name}")
|
|
157
|
-
unless stat.fetch(:stat).exists?
|
|
158
|
-
result = cluster.zk.create(path: "/consumers/#{group.name}/owners/#{topic.name}")
|
|
159
|
-
if result.fetch(:rc) != Zookeeper::Constants::ZOK
|
|
160
|
-
raise Kazoo::ConsumerInstanceRegistrationFailed, "Failed to register subscription of #{topic.name} for consumer group #{group.name}! Error code: #{result.fetch(:rc)}"
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def deregister
|
|
167
|
-
cluster.zk.delete(path: "/consumers/#{group.name}/ids/#{id}")
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def claim_partition(partition)
|
|
171
|
-
result = cluster.zk.create(
|
|
172
|
-
path: "/consumers/#{group.name}/owners/#{partition.topic.name}/#{partition.id}",
|
|
173
|
-
ephemeral: true,
|
|
174
|
-
data: id,
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
case result.fetch(:rc)
|
|
178
|
-
when Zookeeper::Constants::ZOK
|
|
179
|
-
return true
|
|
180
|
-
when Zookeeper::Constants::ZNODEEXISTS
|
|
181
|
-
raise Kazoo::PartitionAlreadyClaimed, "Partition #{partition.topic.name}/#{partition.id} is already claimed!"
|
|
182
|
-
else
|
|
183
|
-
raise Kazoo::Error, "Failed to claim partition #{partition.topic.name}/#{partition.id}. Error code: #{result.fetch(:rc)}"
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def release_partition(partition)
|
|
188
|
-
result = cluster.zk.delete(path: "/consumers/#{group.name}/owners/#{partition.topic.name}/#{partition.id}")
|
|
189
|
-
if result.fetch(:rc) != Zookeeper::Constants::ZOK
|
|
190
|
-
raise Kazoo::Error, "Failed to release partition #{partition.topic.name}/#{partition.id}. Error code: #{result.fetch(:rc)}"
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def inspect
|
|
195
|
-
"#<Kazoo::Consumergroup::Instance group=#{group.name} id=#{id}>"
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def hash
|
|
199
|
-
[group, id].hash
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
def eql?(other)
|
|
203
|
-
other.kind_of?(Kazoo::Consumergroup::Instance) && group == other.group && id == other.id
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
alias_method :==, :eql?
|
|
207
|
-
|
|
208
|
-
private
|
|
209
|
-
|
|
210
|
-
def cluster
|
|
211
|
-
group.cluster
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
end
|
data/lib/kazoo/partition.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
module Kazoo
|
|
2
|
-
class Partition
|
|
3
|
-
attr_reader :topic, :id, :replicas
|
|
4
|
-
|
|
5
|
-
def initialize(topic, id, replicas: nil)
|
|
6
|
-
@topic, @id, @replicas = topic, id, replicas
|
|
7
|
-
@mutex = Mutex.new
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def cluster
|
|
11
|
-
topic.cluster
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def replication_factor
|
|
15
|
-
replicas.length
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def leader
|
|
19
|
-
@mutex.synchronize do
|
|
20
|
-
refresh_state if @leader.nil?
|
|
21
|
-
@leader
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def isr
|
|
26
|
-
@mutex.synchronize do
|
|
27
|
-
refresh_state if @isr.nil?
|
|
28
|
-
@isr
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def under_replicated?
|
|
33
|
-
isr.length < replication_factor
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def inspect
|
|
37
|
-
"#<Kazoo::Partition #{topic.name}/#{id}>"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def eql?(other)
|
|
41
|
-
other.kind_of?(Kazoo::Partition) && topic == other.topic && id == other.id
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
alias_method :==, :eql?
|
|
45
|
-
|
|
46
|
-
def hash
|
|
47
|
-
[topic, id].hash
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
protected
|
|
51
|
-
|
|
52
|
-
def refresh_state
|
|
53
|
-
state_json = cluster.zk.get(path: "/brokers/topics/#{topic.name}/partitions/#{id}/state")
|
|
54
|
-
set_state(JSON.parse(state_json.fetch(:data)))
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def set_state(json)
|
|
58
|
-
@leader = cluster.brokers.fetch(json.fetch('leader'))
|
|
59
|
-
@isr = json.fetch('isr').map { |r| cluster.brokers.fetch(r) }
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
data/lib/kazoo/topic.rb
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
module Kazoo
|
|
2
|
-
class Topic
|
|
3
|
-
|
|
4
|
-
attr_reader :cluster, :name
|
|
5
|
-
attr_accessor :partitions
|
|
6
|
-
|
|
7
|
-
def initialize(cluster, name, partitions: nil)
|
|
8
|
-
@cluster, @name, @partitions = cluster, name, partitions
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def self.from_json(cluster, name, json)
|
|
12
|
-
topic = new(cluster, name)
|
|
13
|
-
topic.partitions = json.fetch('partitions').map do |(id, replicas)|
|
|
14
|
-
topic.partition(id.to_i, replicas: replicas.map { |b| cluster.brokers[b] })
|
|
15
|
-
end.sort_by(&:id)
|
|
16
|
-
|
|
17
|
-
return topic
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def partition(*args)
|
|
21
|
-
Kazoo::Partition.new(self, *args)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def replication_factor
|
|
25
|
-
partitions.map(&:replication_factor).min
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def under_replicated?
|
|
29
|
-
partitions.any?(:under_replicated?)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def inspect
|
|
33
|
-
"#<Kazoo::Topic #{name}>"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def eql?(other)
|
|
37
|
-
other.kind_of?(Kazoo::Topic) && cluster == other.cluster && name == other.name
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
alias_method :==, :eql?
|
|
41
|
-
|
|
42
|
-
def hash
|
|
43
|
-
[cluster, name].hash
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
data/lib/kazoo/version.rb
DELETED
data/test/broker_test.rb
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
class BrokerTest < Minitest::Test
|
|
4
|
-
include MockCluster
|
|
5
|
-
|
|
6
|
-
def setup
|
|
7
|
-
@cluster = mock_cluster
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def test_broker_critical?
|
|
11
|
-
refute @cluster.brokers[1].critical?(replicas: 1), "We have 2 in-sync replicas for everything so we can lose 1."
|
|
12
|
-
assert @cluster.brokers[2].critical?(replicas: 2), "We only have 2 replicas so we can never lose 2."
|
|
13
|
-
|
|
14
|
-
# Simulate losing a broker from the ISR for a partition.
|
|
15
|
-
# This partition lives on broker 1 and 3
|
|
16
|
-
@cluster.topics['test.4'].partitions[2].expects(:isr).returns([@cluster.brokers[1]])
|
|
17
|
-
|
|
18
|
-
assert @cluster.brokers[1].critical?(replicas: 1), "Final remaining broker for this partition's ISR set, cannot lose"
|
|
19
|
-
refute @cluster.brokers[2].critical?(replicas: 1), "Not related to the under-replicated partitions"
|
|
20
|
-
refute @cluster.brokers[3].critical?(replicas: 1), "Already down, so not critical"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def test_from_json
|
|
24
|
-
json_payload = '{"jmx_port":9999,"timestamp":"1431719964125","host":"kafka03.example.com","version":1,"port":9092}'
|
|
25
|
-
broker = Kazoo::Broker.from_json(mock('cluster'), 3, JSON.parse(json_payload))
|
|
26
|
-
|
|
27
|
-
assert_equal 3, broker.id
|
|
28
|
-
assert_equal 'kafka03.example.com', broker.host
|
|
29
|
-
assert_equal 9092, broker.port
|
|
30
|
-
assert_equal 9999, broker.jmx_port
|
|
31
|
-
assert_equal "kafka03.example.com:9092", broker.addr
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def test_replicated_partitions
|
|
35
|
-
assert_equal 3, @cluster.brokers[1].replicated_partitions.length
|
|
36
|
-
assert_equal 4, @cluster.brokers[2].replicated_partitions.length
|
|
37
|
-
assert_equal 3, @cluster.brokers[3].replicated_partitions.length
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def test_led_partitions
|
|
41
|
-
assert_equal 2, @cluster.brokers[1].led_partitions.length
|
|
42
|
-
assert_equal 2, @cluster.brokers[2].led_partitions.length
|
|
43
|
-
assert_equal 1, @cluster.brokers[3].led_partitions.length
|
|
44
|
-
end
|
|
45
|
-
end
|
data/test/cluster_test.rb
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
class ClusterTest < Minitest::Test
|
|
4
|
-
include MockCluster
|
|
5
|
-
|
|
6
|
-
def setup
|
|
7
|
-
@cluster = mock_cluster
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def test_cluster_under_replicated?
|
|
11
|
-
refute @cluster.under_replicated?
|
|
12
|
-
|
|
13
|
-
@cluster.topics['test.4'].partitions[2].expects(:isr).returns([@cluster.brokers[1]])
|
|
14
|
-
assert @cluster.under_replicated?
|
|
15
|
-
end
|
|
16
|
-
end
|
data/test/partition_test.rb
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
class PartitionTest < Minitest::Test
|
|
4
|
-
include MockCluster
|
|
5
|
-
|
|
6
|
-
def setup
|
|
7
|
-
@cluster = mock_cluster
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def test_replication_factor
|
|
11
|
-
assert_equal 2, @cluster.topics['test.1'].partitions[0].replication_factor
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def test_state
|
|
15
|
-
partition = @cluster.topics['test.1'].partitions[0]
|
|
16
|
-
partition.unstub(:leader)
|
|
17
|
-
partition.unstub(:isr)
|
|
18
|
-
|
|
19
|
-
json_payload = '{"controller_epoch":157,"leader":1,"version":1,"leader_epoch":8,"isr":[3,2,1]}'
|
|
20
|
-
@cluster.zk.expects(:get).with(path: "/brokers/topics/test.1/partitions/0/state").returns(data: json_payload)
|
|
21
|
-
|
|
22
|
-
assert_equal 1, partition.leader.id
|
|
23
|
-
assert_equal [3,2,1], partition.isr.map(&:id)
|
|
24
|
-
end
|
|
25
|
-
end
|
data/test/topic_test.rb
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
class TopicTest < Minitest::Test
|
|
4
|
-
include MockCluster
|
|
5
|
-
|
|
6
|
-
def setup
|
|
7
|
-
@cluster = mock_cluster
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def test_from_json
|
|
11
|
-
json_payload = '{"version":1,"partitions":{"2":[1,2,3],"1":[3,1,2],"3":[2,3,1],"0":[3,2,1]}}'
|
|
12
|
-
topic = Kazoo::Topic.from_json(@cluster, 'test.4', JSON.parse(json_payload))
|
|
13
|
-
|
|
14
|
-
assert_equal 4, topic.partitions.length
|
|
15
|
-
assert_equal [3,2,1], topic.partitions[0].replicas.map(&:id)
|
|
16
|
-
assert_equal [3,1,2], topic.partitions[1].replicas.map(&:id)
|
|
17
|
-
assert_equal [1,2,3], topic.partitions[2].replicas.map(&:id)
|
|
18
|
-
assert_equal [2,3,1], topic.partitions[3].replicas.map(&:id)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_replication_factor
|
|
22
|
-
json_payload = '{"version":1,"partitions":{"2":[1,2,3],"1":[3,1,2],"3":[2,3,1],"0":[3,2,1]}}'
|
|
23
|
-
topic = Kazoo::Topic.from_json(@cluster, 'test.4', JSON.parse(json_payload))
|
|
24
|
-
assert_equal 3, topic.replication_factor
|
|
25
|
-
|
|
26
|
-
json_payload = '{"version":1,"partitions":{"2":[2,3],"1":[2],"3":[2,3,1],"0":[3,2,1]}}'
|
|
27
|
-
topic = Kazoo::Topic.from_json(@cluster, 'test.4', JSON.parse(json_payload))
|
|
28
|
-
assert_equal 1, topic.replication_factor
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def tets_topic_under_replicated?
|
|
32
|
-
refute @cluster.topics['test.1'].under_replicated?
|
|
33
|
-
refute @cluster.topics['test.1'].partitions[0].under_replicated?
|
|
34
|
-
|
|
35
|
-
@cluster.topics['test.1'].partitions[0].expects(:isr).returns([@cluster.brokers[1]])
|
|
36
|
-
|
|
37
|
-
assert @cluster.topics['test.1'].partitions[0].under_replicated?
|
|
38
|
-
assert @cluster.topics['test.1'].under_replicated?
|
|
39
|
-
end
|
|
40
|
-
end
|