bps-kafka 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5c35677b45d9df97c7ab28ef3ce4e910d2edcd6def70caa235923b48ab9cd057
4
+ data.tar.gz: 5d4ee5dce8765945dd11a373e4d461e1c5aaf08ee32e77f7e40c64954d934f2e
5
+ SHA512:
6
+ metadata.gz: be7fcda9c77f2f3bb4d29f49bb29ecce4362f0bd41405e6567b93f9ce4c81019e522d3d7bfecb81d52e67d468bbc8e807c562d35cac8a05f1cf01d03d0a7eb61
7
+ data.tar.gz: af85befa5ff134a58df21d247b648b72d2c81206ffe1613c92ae8270d43bcb3ba3d12e9adcd31f3832ff0c2966d04e2ae377f93d5a3c8ff348a360e70f0021a5
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bps-kafka'
3
+ s.version = File.read(File.expand_path('../../.version', __dir__)).strip
4
+ s.platform = Gem::Platform::RUBY
5
+
6
+ s.licenses = ['Apache-2.0']
7
+ s.summary = 'Kafka adapter for bps'
8
+ s.description = 'https://github.com/bsm/bps'
9
+
10
+ s.authors = ['Black Square Media']
11
+ s.email = 'info@blacksquaremedia.com'
12
+ s.homepage = 'https://github.com/bsm/bps'
13
+
14
+ s.executables = []
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
+ s.require_paths = ['lib']
18
+ s.required_ruby_version = '>= 2.6.0'
19
+
20
+ s.add_dependency 'bps', s.version
21
+ s.add_dependency 'ruby-kafka', '>= 1.1.0.beta1'
22
+ end
@@ -0,0 +1 @@
1
+ require 'bps/kafka'
@@ -0,0 +1,18 @@
1
+ require 'bps'
2
+ require 'kafka'
3
+ require 'bps/publisher/kafka'
4
+ require 'bps/publisher/kafka_async'
5
+
6
+ module BPS
7
+ module Publisher
8
+ register('kafka+sync') do |url, **opts|
9
+ addrs = CGI.unescape(url.host).split(',')
10
+ Kafka.new(addrs, **Kafka.coercer.coerce(opts))
11
+ end
12
+
13
+ register('kafka') do |url, **opts|
14
+ addrs = CGI.unescape(url.host).split(',')
15
+ KafkaAsync.new(addrs, **Kafka.coercer.coerce(opts))
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,102 @@
1
+ require 'bps/kafka'
2
+
3
+ module BPS
4
+ module Publisher
5
+ class Kafka < Abstract
6
+ class Topic
7
+ def initialize(producer, topic)
8
+ @producer = producer
9
+ @topic = topic
10
+ end
11
+
12
+ def publish(message, **opts)
13
+ @producer.produce(message, **opts, topic: @topic)
14
+ after_publish
15
+ end
16
+
17
+ def flush
18
+ @producer.deliver_messages
19
+ end
20
+
21
+ protected
22
+
23
+ def after_publish
24
+ @producer.deliver_messages
25
+ nil
26
+ end
27
+ end
28
+
29
+ CLIENT_OPTS = {
30
+ client_id: :string,
31
+ connect_timeout: :float,
32
+ socket_timeout: :float,
33
+ ssl_ca_cert_file_path: :string,
34
+ ssl_ca_cert: :string,
35
+ ssl_client_cert: :string,
36
+ ssl_client_cert_key: :string,
37
+ ssl_client_cert_key_password: :string,
38
+ ssl_client_cert_chain: :string,
39
+ sasl_gssapi_principal: :string,
40
+ sasl_gssapi_keytab: :string,
41
+ sasl_plain_authzid: :string,
42
+ sasl_plain_username: :string,
43
+ sasl_plain_password: :string,
44
+ sasl_scram_username: :string,
45
+ sasl_scram_password: :string,
46
+ sasl_scram_mechanism: :string,
47
+ sasl_over_ssl: :bool,
48
+ ssl_ca_certs_from_system: :bool,
49
+ ssl_verify_hostname: :bool,
50
+ }.freeze
51
+
52
+ PRODUCER_OPTS = {
53
+ # standard
54
+ retry_backoff: :float,
55
+ compression_codec: :symbol,
56
+ compression_threshold: :int,
57
+ ack_timeout: :float,
58
+ required_acks: :symbol,
59
+ max_retries: :int,
60
+ max_buffer_size: :int,
61
+ max_buffer_bytesize: :int,
62
+ idempotent: :bool,
63
+ transactional: :bool,
64
+ transactional_id: :string,
65
+ transactional_timeout: :bool,
66
+ # async
67
+ delivery_interval: :float,
68
+ delivery_threshold: :int,
69
+ max_queue_size: :int,
70
+ }.freeze
71
+
72
+ # @return [BPS::Coercer] the options coercer.
73
+ def self.coercer
74
+ @coercer ||= BPS::Coercer.new(CLIENT_OPTS.merge(PRODUCER_OPTS)).freeze
75
+ end
76
+
77
+ # @param [Array<String>] brokers the seed broker addresses.
78
+ # @param [Hash] opts the options.
79
+ # @see https://www.rubydoc.info/gems/ruby-kafka/Kafka/Client#initialize-instance_method
80
+ def initialize(broker_addrs, **opts)
81
+ @topics = {}
82
+ @client = ::Kafka.new(broker_addrs, **opts.slice(*CLIENT_OPTS.keys))
83
+ @producer = init_producer(**opts.slice(*PRODUCER_OPTS.keys))
84
+ end
85
+
86
+ def topic(name)
87
+ @topics[name] ||= self.class::Topic.new(@producer, name)
88
+ end
89
+
90
+ def close
91
+ @producer.shutdown
92
+ @client.close
93
+ end
94
+
95
+ private
96
+
97
+ def init_producer(**opts)
98
+ @producer = @client.producer(**opts)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,37 @@
1
+ require 'bps/publisher/kafka'
2
+
3
+ module BPS
4
+ module Publisher
5
+ class KafkaAsync < Kafka
6
+ class Topic < Kafka::Topic
7
+ private
8
+
9
+ def after_publish; end
10
+ end
11
+
12
+ # @see BPS::Kafka::Publisher
13
+ #
14
+ # @param [Hash] opts the options.
15
+ # @option opts [Integer] :max_queue_size (defaults to: 1000)
16
+ # the maximum number of messages allowed in the queue.
17
+ # @option opts [Integer] :delivery_threshold (defaults to: 0)
18
+ # if greater than zero, the number of buffered messages that will automatically
19
+ # trigger a delivery.
20
+ # @option opts [Integer] :delivery_interval (defaults to: 0) if greater than zero, the number of
21
+ # seconds between automatic message deliveries.
22
+ def initialize(broker_addrs, **opts)
23
+ super
24
+ end
25
+
26
+ private
27
+
28
+ def init_producer(max_queue_size: 1000, delivery_threshold: 0, delivery_interval: 0)
29
+ @client.async_producer(
30
+ max_queue_size: max_queue_size,
31
+ delivery_threshold: delivery_threshold,
32
+ delivery_interval: delivery_interval,
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'bps/kafka'
3
+
4
+ def kafka_addrs
5
+ ENV.fetch('KAFKA_ADDRS', '127.0.0.1:9092').split(',').freeze
6
+ end
7
+
8
+ run_spec = \
9
+ begin
10
+ ::Kafka.new(kafka_addrs).brokers
11
+ true
12
+ rescue StandardError => e
13
+ warn "WARNING: unable to run #{File.basename __FILE__}: #{e.message}"
14
+ false
15
+ end
16
+
17
+ helper = proc do
18
+ def read_messages(topic_name, num_messages)
19
+ client = ::Kafka.new(kafka_addrs)
20
+ Enumerator.new do |y|
21
+ client.each_message(topic: topic_name, start_from_beginning: true) do |msg|
22
+ y << msg.value
23
+ end
24
+ end.take(num_messages)
25
+ ensure
26
+ client&.close
27
+ end
28
+ end
29
+
30
+ RSpec.describe 'Kafka', if: run_spec do
31
+ context BPS::Publisher::Kafka do
32
+ it_behaves_like 'publisher', url: "kafka+sync://#{kafka_addrs.join(',')}/", &helper
33
+ end
34
+
35
+ context BPS::Publisher::KafkaAsync do
36
+ it_behaves_like 'publisher', url: "kafka://#{kafka_addrs.join(',')}/", &helper
37
+ end
38
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bps-kafka
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Black Square Media
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-07-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bps
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby-kafka
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.0.beta1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.0.beta1
41
+ description: https://github.com/bsm/bps
42
+ email: info@blacksquaremedia.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - bps-kafka.gemspec
48
+ - lib/bps-kafka.rb
49
+ - lib/bps/kafka.rb
50
+ - lib/bps/publisher/kafka.rb
51
+ - lib/bps/publisher/kafka_async.rb
52
+ - spec/bps/kafka_spec.rb
53
+ homepage: https://github.com/bsm/bps
54
+ licenses:
55
+ - Apache-2.0
56
+ metadata: {}
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: 2.6.0
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubygems_version: 3.1.4
73
+ signing_key:
74
+ specification_version: 4
75
+ summary: Kafka adapter for bps
76
+ test_files:
77
+ - spec/bps/kafka_spec.rb