ruby-kafka 0.5.0 → 0.5.1.beta1
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 +33 -0
- data/CHANGELOG.md +8 -0
- data/README.md +29 -7
- data/docker-compose.yml +39 -0
- data/lib/kafka.rb +14 -0
- data/lib/kafka/broker.rb +48 -19
- data/lib/kafka/broker_pool.rb +3 -1
- data/lib/kafka/client.rb +65 -7
- data/lib/kafka/cluster.rb +68 -4
- data/lib/kafka/connection.rb +8 -18
- data/lib/kafka/connection_builder.rb +2 -1
- data/lib/kafka/consumer.rb +16 -4
- data/lib/kafka/fetch_operation.rb +3 -1
- data/lib/kafka/protocol.rb +8 -0
- data/lib/kafka/protocol/api_versions_request.rb +19 -0
- data/lib/kafka/protocol/api_versions_response.rb +47 -0
- data/lib/kafka/protocol/create_topics_request.rb +40 -0
- data/lib/kafka/protocol/create_topics_response.rb +24 -0
- data/lib/kafka/protocol/decoder.rb +9 -0
- data/lib/kafka/protocol/encoder.rb +8 -0
- data/lib/kafka/protocol/fetch_request.rb +4 -2
- data/lib/kafka/protocol/message.rb +13 -1
- data/lib/kafka/protocol/message_set.rb +7 -1
- data/lib/kafka/protocol/metadata_response.rb +10 -2
- data/lib/kafka/protocol/sasl_handshake_request.rb +1 -1
- data/lib/kafka/protocol/topic_metadata_request.rb +4 -0
- data/lib/kafka/round_robin_assignment_strategy.rb +5 -1
- data/lib/kafka/sasl/gssapi.rb +74 -0
- data/lib/kafka/sasl/plain.rb +37 -0
- data/lib/kafka/sasl/scram.rb +175 -0
- data/lib/kafka/sasl_authenticator.rb +31 -39
- data/lib/kafka/version.rb +1 -1
- metadata +14 -8
- data/circle.yml +0 -23
- data/lib/kafka/sasl_gssapi_authenticator.rb +0 -77
- data/lib/kafka/sasl_plain_authenticator.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 872944b4c0fb6b670fac704b827cb2ffa713e8ae
|
4
|
+
data.tar.gz: 17507f698aa6eb93007164d72cb24d2f79d9f2d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5ac176d6dfa6db9ac431cf6a3c7bb1eda4183ef2a0f19864d0904ebb3024861b92ef98083fdf06512ab85c5545c2b93db10e83d8539858817953e9fc2689a4b
|
7
|
+
data.tar.gz: d72d3db50e98dd12840494c0691943d2f332dca639caf0cda65e750ce3109bd03ad194f720129a887100242f19ef52d2a710dd290fa02ec43eafa3f8fa025c2e
|
@@ -0,0 +1,33 @@
|
|
1
|
+
version: 2
|
2
|
+
jobs:
|
3
|
+
build:
|
4
|
+
docker:
|
5
|
+
- image: circleci/ruby:2.4.1-node
|
6
|
+
environment:
|
7
|
+
LOG_LEVEL: DEBUG
|
8
|
+
- image: wurstmeister/zookeeper
|
9
|
+
- image: wurstmeister/kafka:0.10.2.1
|
10
|
+
environment:
|
11
|
+
KAFKA_ADVERTISED_HOST_NAME: localhost
|
12
|
+
KAFKA_ADVERTISED_PORT: 9092
|
13
|
+
KAFKA_PORT: 9092
|
14
|
+
KAFKA_ZOOKEEPER_CONNECT: localhost:2181
|
15
|
+
- image: wurstmeister/kafka:0.10.2.1
|
16
|
+
environment:
|
17
|
+
KAFKA_ADVERTISED_HOST_NAME: localhost
|
18
|
+
KAFKA_ADVERTISED_PORT: 9093
|
19
|
+
KAFKA_PORT: 9093
|
20
|
+
KAFKA_ZOOKEEPER_CONNECT: localhost:2181
|
21
|
+
- image: wurstmeister/kafka:0.10.2.1
|
22
|
+
environment:
|
23
|
+
KAFKA_ADVERTISED_HOST_NAME: localhost
|
24
|
+
KAFKA_ADVERTISED_PORT: 9094
|
25
|
+
KAFKA_PORT: 9094
|
26
|
+
KAFKA_ZOOKEEPER_CONNECT: localhost:2181
|
27
|
+
|
28
|
+
steps:
|
29
|
+
- checkout
|
30
|
+
- run: bundle install --path vendor/bundle
|
31
|
+
- run: bundle exec rspec
|
32
|
+
- run: bundle exec rspec --profile --tag functional spec/functional
|
33
|
+
- run: bundle exec rubocop
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,14 @@ Changes and additions to the library will be listed here.
|
|
4
4
|
|
5
5
|
## Unreleased
|
6
6
|
|
7
|
+
Requires Kafka 0.10.1+ due to usage of a few new APIs.
|
8
|
+
|
9
|
+
- Fix bug when using compression (#458).
|
10
|
+
- Update the v3 of the Fetch API, allowing a per-request `max_bytes` setting (#468).
|
11
|
+
- Make `#deliver_message` more resilient using retries and backoff.
|
12
|
+
- Add support for SASL SCRAM authentication (#465).
|
13
|
+
- Refactor and simplify SASL code.
|
14
|
+
|
7
15
|
## v0.5.0
|
8
16
|
|
9
17
|
- Drops support for Kafka 0.9 in favor of Kafka 0.10 (#381)!
|
data/README.md
CHANGED
@@ -46,6 +46,8 @@ Although parts of this library work with Kafka 0.8 – specifically, the Produce
|
|
46
46
|
6. [Support and Discussion](#support-and-discussion)
|
47
47
|
7. [Roadmap](#roadmap)
|
48
48
|
8. [Higher level libraries](#higher-level-libraries)
|
49
|
+
1. [Message processing frameworks](#message-processing-framework)
|
50
|
+
2. [Message publishing libraries](#message-publishing-libraries)
|
49
51
|
|
50
52
|
## Installation
|
51
53
|
|
@@ -91,7 +93,7 @@ Or install it yourself as:
|
|
91
93
|
|
92
94
|
This library is targeting Kafka 0.9 with the v0.4.x series and Kafka 0.10 with the v0.5.x series. There's limited support for Kafka 0.8, and things should work with Kafka 0.11, although there may be performance issues due to changes in the protocol.
|
93
95
|
|
94
|
-
- **Kafka 0.8:** Full support for the Producer API, but no support for consumer groups. Simple message fetching works.
|
96
|
+
- **Kafka 0.8:** Full support for the Producer API in ruby-kafka v0.4.x, but no support for consumer groups. Simple message fetching works.
|
95
97
|
- **Kafka 0.9:** Full support for the Producer and Consumer API in ruby-kafka v0.4.x.
|
96
98
|
- **Kafka 0.10:** Full support for the Producer and Consumer API in ruby-kafka v0.5.x.
|
97
99
|
- **Kafka 0.11:** Everything that works with Kafka 0.10 should still work, but so far no features specific to Kafka 0.11 have been added.
|
@@ -899,8 +901,9 @@ Typically, Kafka certificates come in the JKS format, which isn't supported by r
|
|
899
901
|
|
900
902
|
#### Authentication using SASL
|
901
903
|
|
902
|
-
Kafka has support for using SASL to authenticate clients. Currently GSSAPI and PLAIN mechanisms are supported by ruby-kafka.
|
904
|
+
Kafka has support for using SASL to authenticate clients. Currently GSSAPI, SCRAM and PLAIN mechanisms are supported by ruby-kafka.
|
903
905
|
|
906
|
+
##### GSSAPI
|
904
907
|
In order to authenticate using GSSAPI, set your principal and optionally your keytab when initializing the Kafka client:
|
905
908
|
|
906
909
|
```ruby
|
@@ -911,6 +914,7 @@ kafka = Kafka.new(
|
|
911
914
|
)
|
912
915
|
```
|
913
916
|
|
917
|
+
##### PLAIN
|
914
918
|
In order to authenticate using PLAIN, you must set your username and password when initializing the Kafka client:
|
915
919
|
|
916
920
|
```ruby
|
@@ -924,6 +928,18 @@ kafka = Kafka.new(
|
|
924
928
|
|
925
929
|
**NOTE**: It is __highly__ recommended that you use SSL for encryption when using SASL_PLAIN
|
926
930
|
|
931
|
+
##### SCRAM
|
932
|
+
Since 0.11 kafka supports [SCRAM](https://kafka.apache.org/documentation.html#security_sasl_scram).
|
933
|
+
|
934
|
+
```ruby
|
935
|
+
kafka = Kafka.new(
|
936
|
+
sasl_scram_username: 'username',
|
937
|
+
sasl_scram_password: 'password',
|
938
|
+
sasl_scram_mechanism: 'sha256',
|
939
|
+
# ...
|
940
|
+
)
|
941
|
+
```
|
942
|
+
|
927
943
|
## Design
|
928
944
|
|
929
945
|
The library has been designed as a layered system, with each layer having a clear responsibility:
|
@@ -978,24 +994,30 @@ Version 0.4 will be the last minor release with support for the Kafka 0.9 protoc
|
|
978
994
|
|
979
995
|
### v0.4
|
980
996
|
|
981
|
-
|
997
|
+
Last stable release with support for the Kafka 0.9 protocol. Bug and security fixes will be released in patch updates.
|
982
998
|
|
983
999
|
### v0.5
|
984
1000
|
|
985
|
-
|
1001
|
+
Latest stable release, with native support for the Kafka 0.10 protocol and eventually newer protocol versions. Kafka 0.9 is no longer supported by this release series.
|
986
1002
|
|
987
1003
|
## Higher level libraries
|
988
1004
|
|
989
|
-
Currently, there are three actively developed frameworks based on ruby-kafka, that provide higher level API that can be used to work with Kafka messages
|
1005
|
+
Currently, there are three actively developed frameworks based on ruby-kafka, that provide higher level API that can be used to work with Kafka messages and two libraries for publishing messages.
|
990
1006
|
|
991
|
-
|
1007
|
+
### Message processing frameworks
|
992
1008
|
|
993
|
-
* [
|
1009
|
+
* [Racecar](https://github.com/zendesk/racecar) - A simple framework that integrates with Ruby on Rails to provide a seamless way to write, test, configure, and run Kafka consumers. It comes with sensible defaults and conventions.
|
994
1010
|
|
995
1011
|
* [Karafka](https://github.com/karafka/karafka) - Framework used to simplify Apache Kafka based Ruby and Rails applications development. Karafka provides higher abstraction layers, including Capistrano, Docker and Heroku support.
|
996
1012
|
|
997
1013
|
* [Phobos](https://github.com/klarna/phobos) - Micro framework and library for applications dealing with Apache Kafka. It wraps common behaviors needed by consumers and producers in an easy and convenient API.
|
998
1014
|
|
1015
|
+
### Message publishing libraries
|
1016
|
+
|
1017
|
+
* [DeliveryBoy](https://github.com/zendesk/delivery_boy) – A library that integrates with Ruby on Rails, making it easy to publish Kafka messages from any Rails application.
|
1018
|
+
|
1019
|
+
* [WaterDrop](https://github.com/karafka/waterdrop) – A library for Ruby and Ruby on Rails applications, to easy publish Kafka messages in both sync and async way.
|
1020
|
+
|
999
1021
|
## Why Create A New Library?
|
1000
1022
|
|
1001
1023
|
There are a few existing Kafka clients in Ruby:
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
version: '2'
|
2
|
+
services:
|
3
|
+
zookeeper:
|
4
|
+
image: wurstmeister/zookeeper
|
5
|
+
ports:
|
6
|
+
- "2181:2181"
|
7
|
+
kafka1:
|
8
|
+
image: wurstmeister/kafka:0.10.2.1
|
9
|
+
ports:
|
10
|
+
- "9092:9092"
|
11
|
+
environment:
|
12
|
+
KAFKA_BROKER_ID: 1
|
13
|
+
KAFKA_ADVERTISED_HOST_NAME: 192.168.99.100
|
14
|
+
KAFKA_ADVERTISED_PORT: 9092
|
15
|
+
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
|
16
|
+
volumes:
|
17
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
18
|
+
kafka2:
|
19
|
+
image: wurstmeister/kafka:0.10.2.1
|
20
|
+
ports:
|
21
|
+
- "9093:9092"
|
22
|
+
environment:
|
23
|
+
KAFKA_BROKER_ID: 2
|
24
|
+
KAFKA_ADVERTISED_HOST_NAME: 192.168.99.100
|
25
|
+
KAFKA_ADVERTISED_PORT: 9093
|
26
|
+
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
|
27
|
+
volumes:
|
28
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
29
|
+
kafka3:
|
30
|
+
image: wurstmeister/kafka:0.10.2.1
|
31
|
+
ports:
|
32
|
+
- "9094:9092"
|
33
|
+
environment:
|
34
|
+
KAFKA_BROKER_ID: 3
|
35
|
+
KAFKA_ADVERTISED_HOST_NAME: 192.168.99.100
|
36
|
+
KAFKA_ADVERTISED_PORT: 9094
|
37
|
+
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
|
38
|
+
volumes:
|
39
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
data/lib/kafka.rb
CHANGED
@@ -21,6 +21,14 @@ module Kafka
|
|
21
21
|
class NoPartitionsToFetchFrom < Error
|
22
22
|
end
|
23
23
|
|
24
|
+
# A message in a partition is larger than the maximum we've asked for.
|
25
|
+
class MessageTooLargeToRead < Error
|
26
|
+
end
|
27
|
+
|
28
|
+
# A connection has been unused for too long, we assume the server has killed it.
|
29
|
+
class IdleConnection < Error
|
30
|
+
end
|
31
|
+
|
24
32
|
# Subclasses of this exception class map to an error code described in the
|
25
33
|
# Kafka protocol specification.
|
26
34
|
#
|
@@ -225,6 +233,12 @@ module Kafka
|
|
225
233
|
class FetchError < Error
|
226
234
|
end
|
227
235
|
|
236
|
+
class SaslScramError < Error
|
237
|
+
end
|
238
|
+
|
239
|
+
class FailedScramAuthentication < SaslScramError
|
240
|
+
end
|
241
|
+
|
228
242
|
# Initializes a new Kafka client.
|
229
243
|
#
|
230
244
|
# @see Client#initialize
|
data/lib/kafka/broker.rb
CHANGED
@@ -4,24 +4,27 @@ require "kafka/protocol"
|
|
4
4
|
|
5
5
|
module Kafka
|
6
6
|
class Broker
|
7
|
-
def initialize(
|
8
|
-
@
|
7
|
+
def initialize(connection_builder:, host:, port:, node_id: nil, logger:)
|
8
|
+
@connection_builder = connection_builder
|
9
|
+
@connection = nil
|
10
|
+
@host = host
|
11
|
+
@port = port
|
9
12
|
@node_id = node_id
|
10
13
|
@logger = logger
|
11
14
|
end
|
12
15
|
|
13
16
|
def address_match?(host, port)
|
14
|
-
@
|
17
|
+
host == @host && port == @port
|
15
18
|
end
|
16
19
|
|
17
20
|
# @return [String]
|
18
21
|
def to_s
|
19
|
-
"#{
|
22
|
+
"#{connection} (node_id=#{@node_id.inspect})"
|
20
23
|
end
|
21
24
|
|
22
25
|
# @return [nil]
|
23
26
|
def disconnect
|
24
|
-
|
27
|
+
connection.close
|
25
28
|
end
|
26
29
|
|
27
30
|
# Fetches cluster metadata from the broker.
|
@@ -31,7 +34,7 @@ module Kafka
|
|
31
34
|
def fetch_metadata(**options)
|
32
35
|
request = Protocol::TopicMetadataRequest.new(**options)
|
33
36
|
|
34
|
-
|
37
|
+
send_request(request)
|
35
38
|
end
|
36
39
|
|
37
40
|
# Fetches messages from a specified topic and partition.
|
@@ -41,7 +44,7 @@ module Kafka
|
|
41
44
|
def fetch_messages(**options)
|
42
45
|
request = Protocol::FetchRequest.new(**options)
|
43
46
|
|
44
|
-
|
47
|
+
send_request(request)
|
45
48
|
end
|
46
49
|
|
47
50
|
# Lists the offset of the specified topics and partitions.
|
@@ -51,7 +54,7 @@ module Kafka
|
|
51
54
|
def list_offsets(**options)
|
52
55
|
request = Protocol::ListOffsetRequest.new(**options)
|
53
56
|
|
54
|
-
|
57
|
+
send_request(request)
|
55
58
|
end
|
56
59
|
|
57
60
|
# Produces a set of messages to the broker.
|
@@ -61,55 +64,81 @@ module Kafka
|
|
61
64
|
def produce(**options)
|
62
65
|
request = Protocol::ProduceRequest.new(**options)
|
63
66
|
|
64
|
-
|
67
|
+
send_request(request)
|
65
68
|
end
|
66
69
|
|
67
70
|
def fetch_offsets(**options)
|
68
71
|
request = Protocol::OffsetFetchRequest.new(**options)
|
69
72
|
|
70
|
-
|
73
|
+
send_request(request)
|
71
74
|
end
|
72
75
|
|
73
76
|
def commit_offsets(**options)
|
74
77
|
request = Protocol::OffsetCommitRequest.new(**options)
|
75
78
|
|
76
|
-
|
79
|
+
send_request(request)
|
77
80
|
end
|
78
81
|
|
79
82
|
def join_group(**options)
|
80
83
|
request = Protocol::JoinGroupRequest.new(**options)
|
81
84
|
|
82
|
-
|
85
|
+
send_request(request)
|
83
86
|
end
|
84
87
|
|
85
88
|
def sync_group(**options)
|
86
89
|
request = Protocol::SyncGroupRequest.new(**options)
|
87
90
|
|
88
|
-
|
91
|
+
send_request(request)
|
89
92
|
end
|
90
93
|
|
91
94
|
def leave_group(**options)
|
92
95
|
request = Protocol::LeaveGroupRequest.new(**options)
|
93
96
|
|
94
|
-
|
97
|
+
send_request(request)
|
95
98
|
end
|
96
99
|
|
97
100
|
def find_group_coordinator(**options)
|
98
101
|
request = Protocol::GroupCoordinatorRequest.new(**options)
|
99
102
|
|
100
|
-
|
103
|
+
send_request(request)
|
101
104
|
end
|
102
105
|
|
103
106
|
def heartbeat(**options)
|
104
107
|
request = Protocol::HeartbeatRequest.new(**options)
|
105
108
|
|
106
|
-
|
109
|
+
send_request(request)
|
107
110
|
end
|
108
111
|
|
109
|
-
def
|
110
|
-
request = Protocol::
|
112
|
+
def create_topics(**options)
|
113
|
+
request = Protocol::CreateTopicsRequest.new(**options)
|
111
114
|
|
112
|
-
|
115
|
+
send_request(request)
|
116
|
+
end
|
117
|
+
|
118
|
+
def api_versions
|
119
|
+
request = Protocol::ApiVersionsRequest.new
|
120
|
+
|
121
|
+
send_request(request)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def send_request(request)
|
127
|
+
connection.send_request(request)
|
128
|
+
rescue IdleConnection
|
129
|
+
@logger.warn "Connection has been unused for too long, re-connecting..."
|
130
|
+
@connection.close rescue nil
|
131
|
+
@connection = nil
|
132
|
+
retry
|
133
|
+
rescue ConnectionError
|
134
|
+
@connection.close rescue nil
|
135
|
+
@connection = nil
|
136
|
+
|
137
|
+
raise
|
138
|
+
end
|
139
|
+
|
140
|
+
def connection
|
141
|
+
@connection ||= @connection_builder.build_connection(@host, @port)
|
113
142
|
end
|
114
143
|
end
|
115
144
|
end
|
data/lib/kafka/broker_pool.rb
CHANGED
data/lib/kafka/client.rb
CHANGED
@@ -49,11 +49,18 @@ module Kafka
|
|
49
49
|
#
|
50
50
|
# @param sasl_gssapi_keytab [String, nil] a KRB5 keytab filepath
|
51
51
|
#
|
52
|
+
# @param sasl_scram_username [String, nil] SCRAM username
|
53
|
+
#
|
54
|
+
# @param sasl_scram_password [String, nil] SCRAM password
|
55
|
+
#
|
56
|
+
# @param sasl_scram_mechanism [String, nil] Scram mechanism, either "sha256" or "sha512"
|
57
|
+
#
|
52
58
|
# @return [Client]
|
53
59
|
def initialize(seed_brokers:, client_id: "ruby-kafka", logger: nil, connect_timeout: nil, socket_timeout: nil,
|
54
60
|
ssl_ca_cert_file_path: nil, ssl_ca_cert: nil, ssl_client_cert: nil, ssl_client_cert_key: nil,
|
55
61
|
sasl_gssapi_principal: nil, sasl_gssapi_keytab: nil,
|
56
|
-
sasl_plain_authzid: '', sasl_plain_username: nil, sasl_plain_password: nil
|
62
|
+
sasl_plain_authzid: '', sasl_plain_username: nil, sasl_plain_password: nil,
|
63
|
+
sasl_scram_username: nil, sasl_scram_password: nil, sasl_scram_mechanism: nil)
|
57
64
|
@logger = logger || Logger.new(nil)
|
58
65
|
@instrumenter = Instrumenter.new(client_id: client_id)
|
59
66
|
@seed_brokers = normalize_seed_brokers(seed_brokers)
|
@@ -66,6 +73,9 @@ module Kafka
|
|
66
73
|
sasl_plain_authzid: sasl_plain_authzid,
|
67
74
|
sasl_plain_username: sasl_plain_username,
|
68
75
|
sasl_plain_password: sasl_plain_password,
|
76
|
+
sasl_scram_username: sasl_scram_username,
|
77
|
+
sasl_scram_password: sasl_scram_password,
|
78
|
+
sasl_scram_mechanism: sasl_scram_mechanism,
|
69
79
|
logger: @logger
|
70
80
|
)
|
71
81
|
|
@@ -96,8 +106,10 @@ module Kafka
|
|
96
106
|
# chosen at random.
|
97
107
|
# @param partition_key [String] a value used to deterministically choose a
|
98
108
|
# partition to write to.
|
109
|
+
# @param retries [Integer] the number of times to retry the delivery before giving
|
110
|
+
# up.
|
99
111
|
# @return [nil]
|
100
|
-
def deliver_message(value, key: nil, topic:, partition: nil, partition_key: nil)
|
112
|
+
def deliver_message(value, key: nil, topic:, partition: nil, partition_key: nil, retries: 1)
|
101
113
|
create_time = Time.now
|
102
114
|
|
103
115
|
message = PendingMessage.new(
|
@@ -140,10 +152,27 @@ module Kafka
|
|
140
152
|
instrumenter: @instrumenter,
|
141
153
|
)
|
142
154
|
|
143
|
-
|
155
|
+
attempt = 1
|
156
|
+
|
157
|
+
begin
|
158
|
+
operation.execute
|
159
|
+
|
160
|
+
unless buffer.empty?
|
161
|
+
raise DeliveryFailed.new(nil, [message])
|
162
|
+
end
|
163
|
+
rescue Kafka::Error => e
|
164
|
+
@cluster.mark_as_stale!
|
144
165
|
|
145
|
-
|
146
|
-
|
166
|
+
if attempt >= (retries + 1)
|
167
|
+
raise
|
168
|
+
else
|
169
|
+
attempt += 1
|
170
|
+
@logger.warn "Error while delivering message, #{e.class}: #{e.message}; retrying after 1s..."
|
171
|
+
|
172
|
+
sleep 1
|
173
|
+
|
174
|
+
retry
|
175
|
+
end
|
147
176
|
end
|
148
177
|
end
|
149
178
|
|
@@ -345,17 +374,32 @@ module Kafka
|
|
345
374
|
# expect messages to be larger than this.
|
346
375
|
#
|
347
376
|
# @return [Array<Kafka::FetchedMessage>] the messages returned from the broker.
|
348
|
-
def fetch_messages(topic:, partition:, offset: :latest, max_wait_time: 5, min_bytes: 1, max_bytes: 1048576)
|
377
|
+
def fetch_messages(topic:, partition:, offset: :latest, max_wait_time: 5, min_bytes: 1, max_bytes: 1048576, retries: 1)
|
349
378
|
operation = FetchOperation.new(
|
350
379
|
cluster: @cluster,
|
351
380
|
logger: @logger,
|
352
381
|
min_bytes: min_bytes,
|
382
|
+
max_bytes: max_bytes,
|
353
383
|
max_wait_time: max_wait_time,
|
354
384
|
)
|
355
385
|
|
356
386
|
operation.fetch_from_partition(topic, partition, offset: offset, max_bytes: max_bytes)
|
357
387
|
|
358
|
-
|
388
|
+
attempt = 1
|
389
|
+
|
390
|
+
begin
|
391
|
+
operation.execute.flat_map {|batch| batch.messages }
|
392
|
+
rescue Kafka::Error => e
|
393
|
+
@cluster.mark_as_stale!
|
394
|
+
|
395
|
+
if attempt >= (retries + 1)
|
396
|
+
raise
|
397
|
+
else
|
398
|
+
attempt += 1
|
399
|
+
@logger.warn "Error while fetching messages, #{e.class}: #{e.message}; retrying..."
|
400
|
+
retry
|
401
|
+
end
|
402
|
+
end
|
359
403
|
end
|
360
404
|
|
361
405
|
# Enumerate all messages in a topic.
|
@@ -407,6 +451,10 @@ module Kafka
|
|
407
451
|
end
|
408
452
|
end
|
409
453
|
|
454
|
+
def create_topic(name, **options)
|
455
|
+
@cluster.create_topic(name, **options)
|
456
|
+
end
|
457
|
+
|
410
458
|
# Lists all topics in the cluster.
|
411
459
|
#
|
412
460
|
# @return [Array<String>] the list of topic names.
|
@@ -415,6 +463,12 @@ module Kafka
|
|
415
463
|
@cluster.topics
|
416
464
|
end
|
417
465
|
|
466
|
+
def has_topic?(topic)
|
467
|
+
@cluster.clear_target_topics
|
468
|
+
@cluster.add_target_topics([topic])
|
469
|
+
@cluster.topics.include?(topic)
|
470
|
+
end
|
471
|
+
|
418
472
|
# Counts the number of partitions in a topic.
|
419
473
|
#
|
420
474
|
# @param topic [String]
|
@@ -455,6 +509,10 @@ module Kafka
|
|
455
509
|
}.to_h
|
456
510
|
end
|
457
511
|
|
512
|
+
def apis
|
513
|
+
@cluster.apis
|
514
|
+
end
|
515
|
+
|
458
516
|
# Closes all connections to the Kafka brokers and frees up used resources.
|
459
517
|
#
|
460
518
|
# @return [nil]
|