rom-kafka 0.0.1
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 +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +9 -0
- data/.metrics +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +34 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +7 -0
- data/Guardfile +14 -0
- data/LICENSE +21 -0
- data/README.md +83 -0
- data/Rakefile +34 -0
- data/config/metrics/STYLEGUIDE +230 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +14 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +71 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +6 -0
- data/config/metrics/yardstick.yml +37 -0
- data/lib/rom-kafka.rb +3 -0
- data/lib/rom/kafka.rb +29 -0
- data/lib/rom/kafka/brokers.rb +72 -0
- data/lib/rom/kafka/brokers/broker.rb +68 -0
- data/lib/rom/kafka/connection.rb +22 -0
- data/lib/rom/kafka/connection/consumer.rb +105 -0
- data/lib/rom/kafka/connection/producer.rb +114 -0
- data/lib/rom/kafka/create.rb +75 -0
- data/lib/rom/kafka/dataset.rb +132 -0
- data/lib/rom/kafka/gateway.rb +165 -0
- data/lib/rom/kafka/relation.rb +78 -0
- data/lib/rom/kafka/version.rb +13 -0
- data/rom-kafka.gemspec +33 -0
- data/spec/integration/basic_usage_spec.rb +58 -0
- data/spec/integration/keys_usage_spec.rb +34 -0
- data/spec/shared/scholars_topic.rb +28 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/unit/brokers/broker_spec.rb +89 -0
- data/spec/unit/brokers_spec.rb +46 -0
- data/spec/unit/connection/consumer_spec.rb +90 -0
- data/spec/unit/connection/producer_spec.rb +79 -0
- data/spec/unit/create_spec.rb +79 -0
- data/spec/unit/dataset_spec.rb +165 -0
- data/spec/unit/gateway_spec.rb +171 -0
- data/spec/unit/relation_spec.rb +96 -0
- metadata +219 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
---
|
2
|
+
folders: # The list of folders to be used by any metric.
|
3
|
+
- lib
|
4
|
+
metrics: # The list of allowed metrics. The other metrics are disabled.
|
5
|
+
- cane
|
6
|
+
- churn
|
7
|
+
- flay
|
8
|
+
- flog
|
9
|
+
- reek
|
10
|
+
- roodi
|
11
|
+
- saikuro
|
12
|
+
format: html
|
13
|
+
output: tmp/metric_fu
|
14
|
+
verbose: false
|
@@ -0,0 +1 @@
|
|
1
|
+
---
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
AssignmentInConditionalCheck:
|
3
|
+
CaseMissingElseCheck:
|
4
|
+
ClassLineCountCheck:
|
5
|
+
line_count: 200
|
6
|
+
ClassNameCheck:
|
7
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
8
|
+
ClassVariableCheck:
|
9
|
+
CyclomaticComplexityBlockCheck:
|
10
|
+
complexity: 3
|
11
|
+
CyclomaticComplexityMethodCheck:
|
12
|
+
complexity: 5
|
13
|
+
EmptyRescueBodyCheck:
|
14
|
+
ForLoopCheck:
|
15
|
+
MethodLineCountCheck:
|
16
|
+
line_count: 6
|
17
|
+
MethodNameCheck:
|
18
|
+
pattern: !ruby/regexp /^[\||\^|\&|\!]$|^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
19
|
+
ModuleLineCountCheck:
|
20
|
+
line_count: 200
|
21
|
+
ModuleNameCheck:
|
22
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
23
|
+
ParameterNumberCheck:
|
24
|
+
parameter_count: 5
|
@@ -0,0 +1,71 @@
|
|
1
|
+
---
|
2
|
+
AllCops:
|
3
|
+
Exclude:
|
4
|
+
- '**/db/schema.rb'
|
5
|
+
|
6
|
+
Lint/HandleExceptions:
|
7
|
+
Exclude:
|
8
|
+
- '**/*_spec.rb'
|
9
|
+
|
10
|
+
Lint/RescueException:
|
11
|
+
Exclude:
|
12
|
+
- '**/*_spec.rb'
|
13
|
+
|
14
|
+
Style/AccessorMethodName:
|
15
|
+
Exclude:
|
16
|
+
- '**/*_spec.rb'
|
17
|
+
|
18
|
+
Style/AsciiComments:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/ClassAndModuleChildren:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Style/Documentation:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Style/EmptyLinesAroundBlockBody:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Style/EmptyLinesAroundClassBody:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Style/EmptyLinesAroundMethodBody:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Style/EmptyLinesAroundModuleBody:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Style/EmptyLineBetweenDefs:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
Style/FileName:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Style/NumericLiterals:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Style/RaiseArgs:
|
49
|
+
EnforcedStyle: compact
|
50
|
+
|
51
|
+
Style/SingleLineMethods:
|
52
|
+
Exclude:
|
53
|
+
- '**/*_spec.rb'
|
54
|
+
|
55
|
+
Style/SingleSpaceBeforeFirstArg:
|
56
|
+
Enabled: false
|
57
|
+
|
58
|
+
Style/SpecialGlobalVars:
|
59
|
+
Exclude:
|
60
|
+
- '**/Gemfile'
|
61
|
+
- '**/*.gemspec'
|
62
|
+
|
63
|
+
Style/StringLiterals:
|
64
|
+
EnforcedStyle: double_quotes
|
65
|
+
|
66
|
+
Style/StringLiteralsInInterpolation:
|
67
|
+
EnforcedStyle: double_quotes
|
68
|
+
|
69
|
+
Style/TrivialAccessors:
|
70
|
+
Exclude:
|
71
|
+
- '**/*_spec.rb'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
---
|
2
|
+
# Settings added by the 'hexx-suit' gem
|
3
|
+
output: "tmp/yardstick/output.log"
|
4
|
+
path: "lib/**/*.rb"
|
5
|
+
rules:
|
6
|
+
ApiTag::Presence:
|
7
|
+
enabled: true
|
8
|
+
exclude: []
|
9
|
+
ApiTag::Inclusion:
|
10
|
+
enabled: true
|
11
|
+
exclude: []
|
12
|
+
ApiTag::ProtectedMethod:
|
13
|
+
enabled: true
|
14
|
+
exclude: []
|
15
|
+
ApiTag::PrivateMethod:
|
16
|
+
enabled: false
|
17
|
+
exclude: []
|
18
|
+
ExampleTag:
|
19
|
+
enabled: true
|
20
|
+
exclude: []
|
21
|
+
ReturnTag:
|
22
|
+
enabled: true
|
23
|
+
exclude: []
|
24
|
+
Summary::Presence:
|
25
|
+
enabled: true
|
26
|
+
exclude: []
|
27
|
+
Summary::Length:
|
28
|
+
enabled: true
|
29
|
+
exclude: []
|
30
|
+
Summary::Delimiter:
|
31
|
+
enabled: true
|
32
|
+
exclude: []
|
33
|
+
Summary::SingleLine:
|
34
|
+
enabled: true
|
35
|
+
exclude: []
|
36
|
+
threshold: 100
|
37
|
+
verbose: false
|
data/lib/rom-kafka.rb
ADDED
data/lib/rom/kafka.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "attributes_dsl"
|
3
|
+
require "poseidon"
|
4
|
+
require "rom"
|
5
|
+
|
6
|
+
# Ruby Object Mapper
|
7
|
+
#
|
8
|
+
# @see http://rom-rb.org/
|
9
|
+
#
|
10
|
+
module ROM
|
11
|
+
|
12
|
+
# Apache Kafka support for ROM
|
13
|
+
#
|
14
|
+
# @see http://kafka.apache.org/
|
15
|
+
#
|
16
|
+
module Kafka
|
17
|
+
|
18
|
+
require_relative "kafka/brokers"
|
19
|
+
require_relative "kafka/connection"
|
20
|
+
require_relative "kafka/dataset"
|
21
|
+
require_relative "kafka/gateway"
|
22
|
+
require_relative "kafka/relation"
|
23
|
+
require_relative "kafka/create"
|
24
|
+
|
25
|
+
end # module Kafka
|
26
|
+
|
27
|
+
register_adapter(:kafka, Kafka)
|
28
|
+
|
29
|
+
end # module ROM
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative "brokers/broker"
|
4
|
+
|
5
|
+
module ROM::Kafka
|
6
|
+
|
7
|
+
# Value object describing a collection of brokers (host:port)
|
8
|
+
#
|
9
|
+
# Knows how to extract brokers from address lines and options
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# brokers = Brokers.new(
|
13
|
+
# "localhost:9092",
|
14
|
+
# "127.0.0.1",
|
15
|
+
# hosts: ["127.0.0.2:9094"],
|
16
|
+
# port: 9093,
|
17
|
+
# unknown_key: :foo # will be ignored by the initializer
|
18
|
+
# )
|
19
|
+
#
|
20
|
+
# brokers.to_a
|
21
|
+
# # => ["localhost:9092", "127.0.0.2:9093", "127.0.0.3:9094"]
|
22
|
+
#
|
23
|
+
# @author Andrew Kozin <Andrew.Kozin@gmail.com>
|
24
|
+
#
|
25
|
+
class Brokers
|
26
|
+
|
27
|
+
include Equalizer.new(:to_a)
|
28
|
+
|
29
|
+
# @!method initialize(lines, options)
|
30
|
+
# Initializes an immutable collection from address lines and/or options
|
31
|
+
#
|
32
|
+
# The initializer is options-tolerant: it just ignores unknown options.
|
33
|
+
#
|
34
|
+
# @param [#to_s, Array<#to_s>] lines
|
35
|
+
# @param [Hash] options
|
36
|
+
#
|
37
|
+
# @option options [#to_s, Array<#to_s>] :hosts
|
38
|
+
# @option options [#to_i] :port
|
39
|
+
#
|
40
|
+
def initialize(*lines)
|
41
|
+
hosts, port = extract_hosts_and_port(lines)
|
42
|
+
@brokers = extract_brokers(hosts, port)
|
43
|
+
|
44
|
+
IceNine.deep_freeze(self)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns array of string representations of brokers
|
48
|
+
#
|
49
|
+
# @return [Array<String>]
|
50
|
+
#
|
51
|
+
def to_a
|
52
|
+
@brokers.map(&:to_s)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def extract_hosts_and_port(lines)
|
58
|
+
options = lines.last.instance_of?(Hash) ? lines.pop : {}
|
59
|
+
port = options[:port]
|
60
|
+
hosts = (lines + Array[options[:hosts]]).compact.flatten
|
61
|
+
|
62
|
+
[hosts, port]
|
63
|
+
end
|
64
|
+
|
65
|
+
def extract_brokers(hosts, port)
|
66
|
+
brokers = hosts.map { |host| Broker.new(host: host, port: port) }
|
67
|
+
brokers.any? ? brokers : [Broker.new]
|
68
|
+
end
|
69
|
+
|
70
|
+
end # class Brokers
|
71
|
+
|
72
|
+
end # module ROM::Kafka
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Kafka
|
4
|
+
|
5
|
+
class Brokers
|
6
|
+
|
7
|
+
# Describes an address to a brocker
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# broker = Broker.new host: "localhost:9092"
|
11
|
+
# broker.to_s # => "localhost:9092"
|
12
|
+
#
|
13
|
+
# broker = Broker.new host: "localhost", port: 9092
|
14
|
+
# broker.to_s # => "localhost:9092"
|
15
|
+
#
|
16
|
+
# broker = Broker.new host: "localhost:9092", port: 9093
|
17
|
+
# broker.to_s # => "localhost:9092"
|
18
|
+
#
|
19
|
+
# @author Andrew Kozin <Andrew.Kozin@gmail.com>
|
20
|
+
#
|
21
|
+
class Broker
|
22
|
+
|
23
|
+
include Equalizer.new(:port, :host)
|
24
|
+
|
25
|
+
# Regex to extract host from address line
|
26
|
+
HOST = %r{^\w+(\:\/\/)?\S+(?=\:)|\S+}.freeze
|
27
|
+
|
28
|
+
# Regex to extract port from address line
|
29
|
+
PORT = /(?!\:)\d{4,5}$/.freeze
|
30
|
+
|
31
|
+
# @!attribute [r] host
|
32
|
+
#
|
33
|
+
# @return [String] the host of the broker
|
34
|
+
#
|
35
|
+
attr_reader :host
|
36
|
+
|
37
|
+
# @!attribute [r] port
|
38
|
+
#
|
39
|
+
# @return [Integer] the port of the broker
|
40
|
+
#
|
41
|
+
attr_reader :port
|
42
|
+
|
43
|
+
# Initializes a value object from host line and port
|
44
|
+
#
|
45
|
+
# @option options [#to_s] :host ("localhost")
|
46
|
+
# @option options [#to_i] :port (9092)
|
47
|
+
#
|
48
|
+
def initialize(options = {})
|
49
|
+
line = options.fetch(:host) { "localhost" }
|
50
|
+
@host = line[HOST]
|
51
|
+
@port = (line[PORT] || options.fetch(:port) { 9092 }).to_i
|
52
|
+
|
53
|
+
IceNine.deep_freeze(self)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the string representation of the broker in "host:port" format
|
57
|
+
#
|
58
|
+
# @return [String]
|
59
|
+
#
|
60
|
+
def to_s
|
61
|
+
"#{host}:#{port}"
|
62
|
+
end
|
63
|
+
|
64
|
+
end # class Broker
|
65
|
+
|
66
|
+
end # class Brokers
|
67
|
+
|
68
|
+
end # module ROM::Kafka
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Kafka
|
4
|
+
|
5
|
+
# Describes the connection to Kafka cluster
|
6
|
+
#
|
7
|
+
# This is a base abstract class for producer and concumer connections.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
# @author Andrew Kozin <Andrew.Kozin@gmail.com>
|
12
|
+
#
|
13
|
+
class Connection
|
14
|
+
|
15
|
+
extend AttributesDSL
|
16
|
+
|
17
|
+
require_relative "connection/producer"
|
18
|
+
require_relative "connection/consumer"
|
19
|
+
|
20
|
+
end # class Connection
|
21
|
+
|
22
|
+
end # module ROM::Kafka
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Kafka
|
4
|
+
|
5
|
+
class Connection
|
6
|
+
|
7
|
+
# The consumer-specific connection to Kafka cluster
|
8
|
+
#
|
9
|
+
# It is wrapped around `Poseidon::Consumer` driver, and responsible for
|
10
|
+
# adopting poseidon API to ROM::Dataset via [#initializer] and [#each]
|
11
|
+
# methods.
|
12
|
+
#
|
13
|
+
# ROM::Kafka consumer deals with tuples, hiding poseidon-specific
|
14
|
+
# implementation of fetched messages from the rest of the gem.
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
class Consumer < Connection
|
19
|
+
|
20
|
+
include Enumerable
|
21
|
+
|
22
|
+
# The 'poseidon'-specific class describing consumers
|
23
|
+
#
|
24
|
+
# @return [Class]
|
25
|
+
#
|
26
|
+
DRIVER = Poseidon::PartitionConsumer
|
27
|
+
|
28
|
+
# Attributes acceptable by the `Poseidon::Consumer` driver
|
29
|
+
attribute :min_bytes
|
30
|
+
attribute :max_bytes
|
31
|
+
attribute :max_wait_ms
|
32
|
+
|
33
|
+
# @!attribute [r] connection
|
34
|
+
#
|
35
|
+
# @return [ROM::Kafka::Connection::Consumer::DRIVER] driver to Kafka
|
36
|
+
#
|
37
|
+
attr_reader :connection
|
38
|
+
|
39
|
+
# Initializes a consumer connection
|
40
|
+
#
|
41
|
+
# The initializer is attributes-agnostic. This means it doesn't validate
|
42
|
+
# attributes, but skips unused.
|
43
|
+
#
|
44
|
+
# @option opts [#to_s] :client_id
|
45
|
+
# A required unique id used to indentify the Kafka client.
|
46
|
+
# @option opts [Array<String>] :brokers
|
47
|
+
# A list of seed brokers to find a lead broker to fetch messages from.
|
48
|
+
# @option opts [String] :topic
|
49
|
+
# A name of the topic to fetch messages from.
|
50
|
+
# @option opts [Integer] :partition
|
51
|
+
# A number of partition to fetch messages from.
|
52
|
+
# @option opts [Integer] :offset
|
53
|
+
# An initial offset to start fetching from.
|
54
|
+
# @option opts [Integer] :min_bytes (1)
|
55
|
+
# A smallest amount of data the server should send.
|
56
|
+
# (By default send us data as soon as it is ready).
|
57
|
+
# @option opts [Integer] :max_bytes (1_048_576)
|
58
|
+
# A maximum number of bytes to fetch by consumer (1MB by default).
|
59
|
+
# @option opts [Integer] :max_wait_ms (100)
|
60
|
+
# How long to block until the server sends data.
|
61
|
+
# NOTE: This is only enforced if min_bytes is > 0.
|
62
|
+
#
|
63
|
+
def initialize(opts)
|
64
|
+
super # takes declared attributes from options
|
65
|
+
args = opts.values_at(:client_id, :brokers, :topic, :partition, :offset)
|
66
|
+
@connection = DRIVER.consumer_for_partition(*args, attributes)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Fetches a single portion of messages and converts them to tuple
|
70
|
+
#
|
71
|
+
# @return [Array<Hash{Symbol => String, Integer}>]
|
72
|
+
#
|
73
|
+
def fetch
|
74
|
+
result = @connection.fetch
|
75
|
+
result.map(&method(:tuple))
|
76
|
+
end
|
77
|
+
|
78
|
+
# Iterates through Kafka messages
|
79
|
+
#
|
80
|
+
# Fetches the next portion of messages until no messages given
|
81
|
+
#
|
82
|
+
# @return [Enumerator<Array<Hash{Symbol => String, Integer}>>]
|
83
|
+
#
|
84
|
+
# @yieldparam [Hash{Symbol => String, Integer}] tuple
|
85
|
+
#
|
86
|
+
def each
|
87
|
+
return to_enum unless block_given?
|
88
|
+
loop do
|
89
|
+
tuples = fetch
|
90
|
+
break unless tuples.any?
|
91
|
+
tuples.each { |tuple| yield(tuple) }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def tuple(msg)
|
98
|
+
{ value: msg.value, topic: msg.topic, key: msg.key, offset: msg.offset }
|
99
|
+
end
|
100
|
+
|
101
|
+
end # class Consumer
|
102
|
+
|
103
|
+
end # class Connection
|
104
|
+
|
105
|
+
end # module ROM::Kafka
|