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.
- checksums.yaml +7 -0
- data/bps-kafka.gemspec +22 -0
- data/lib/bps-kafka.rb +1 -0
- data/lib/bps/kafka.rb +18 -0
- data/lib/bps/publisher/kafka.rb +102 -0
- data/lib/bps/publisher/kafka_async.rb +37 -0
- data/spec/bps/kafka_spec.rb +38 -0
- metadata +77 -0
    
        checksums.yaml
    ADDED
    
    | @@ -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
         | 
    
        data/bps-kafka.gemspec
    ADDED
    
    | @@ -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
         | 
    
        data/lib/bps-kafka.rb
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            require 'bps/kafka'
         | 
    
        data/lib/bps/kafka.rb
    ADDED
    
    | @@ -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
         |