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