racecar 0.5.0.beta2 → 2.2.0
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 +5 -5
- data/.circleci/config.yml +56 -0
- data/.github/workflows/ci.yml +61 -0
- data/.gitignore +0 -1
- data/CHANGELOG.md +48 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +69 -0
- data/README.md +56 -59
- data/Rakefile +2 -0
- data/docker-compose.yml +32 -0
- data/examples/batch_consumer.rb +2 -0
- data/examples/cat_consumer.rb +2 -0
- data/examples/producing_consumer.rb +2 -0
- data/exe/racecar +36 -13
- data/lib/ensure_hash_compact.rb +12 -0
- data/lib/generators/racecar/consumer_generator.rb +2 -0
- data/lib/generators/racecar/install_generator.rb +2 -0
- data/lib/racecar.rb +20 -14
- data/lib/racecar/cli.rb +25 -22
- data/lib/racecar/config.rb +109 -45
- data/lib/racecar/consumer.rb +52 -11
- data/lib/racecar/consumer_set.rb +239 -0
- data/lib/racecar/ctl.rb +8 -8
- data/lib/racecar/daemon.rb +2 -0
- data/lib/racecar/datadog.rb +247 -0
- data/lib/racecar/instrumenter.rb +28 -0
- data/lib/racecar/message.rb +30 -0
- data/lib/racecar/null_instrumenter.rb +10 -0
- data/lib/racecar/pause.rb +59 -0
- data/lib/racecar/rails_config_file_loader.rb +2 -0
- data/lib/racecar/runner.rb +222 -113
- data/lib/racecar/version.rb +3 -1
- data/racecar.gemspec +7 -3
- metadata +91 -13
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: e2c32338556d27bfcbae35df0758163a457d2c6e3f520141206c5a9c0124cc68
         | 
| 4 | 
            +
              data.tar.gz: 43d9c42d0d483c269b15d417ef59e2985da3ca3945d34d6772f8dd262ccbfaf6
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0467ac1cdefb6cad9870dd73b92f4a5a943b9f685ff3fc876b3f183d109ae3d29d7c2c7dffea8f31bca7c7b18565e5aba04d4865c94f2448a7228be175855a5b
         | 
| 7 | 
            +
              data.tar.gz: e4ab43eb180995af916d447b006438b4a48cb808b29aabec52b455e246541a083192d1b560a957fa6f3ab7d5412dd12ab74aac49acc0b606c3df87cec90b93b6
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            version: 2.1
         | 
| 2 | 
            +
            orbs:
         | 
| 3 | 
            +
              ruby: circleci/ruby@0.1.2
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            jobs:
         | 
| 6 | 
            +
              build:
         | 
| 7 | 
            +
                docker:
         | 
| 8 | 
            +
                  - image: circleci/ruby:2.6.3-stretch-node
         | 
| 9 | 
            +
                executor: ruby/default
         | 
| 10 | 
            +
                steps:
         | 
| 11 | 
            +
                  - checkout
         | 
| 12 | 
            +
                  - run:
         | 
| 13 | 
            +
                      name: Which bundler?
         | 
| 14 | 
            +
                      command: bundle -v
         | 
| 15 | 
            +
                  - ruby/bundle-install
         | 
| 16 | 
            +
                  - run: bundle exec rspec --exclude-pattern='spec/integration/*_spec.rb'
         | 
| 17 | 
            +
              integration-tests:
         | 
| 18 | 
            +
                docker:
         | 
| 19 | 
            +
                  - image: circleci/ruby:2.6.3-stretch-node
         | 
| 20 | 
            +
                  - image: wurstmeister/zookeeper
         | 
| 21 | 
            +
                  - image: wurstmeister/kafka:2.11-2.0.0
         | 
| 22 | 
            +
                    environment:
         | 
| 23 | 
            +
                      KAFKA_ADVERTISED_HOST_NAME: localhost
         | 
| 24 | 
            +
                      KAFKA_ADVERTISED_PORT: 9092
         | 
| 25 | 
            +
                      KAFKA_PORT: 9092
         | 
| 26 | 
            +
                      KAFKA_ZOOKEEPER_CONNECT: localhost:2181
         | 
| 27 | 
            +
                      KAFKA_DELETE_TOPIC_ENABLE: true
         | 
| 28 | 
            +
                  - image: wurstmeister/kafka:2.11-2.0.0
         | 
| 29 | 
            +
                    environment:
         | 
| 30 | 
            +
                      KAFKA_ADVERTISED_HOST_NAME: localhost
         | 
| 31 | 
            +
                      KAFKA_ADVERTISED_PORT: 9093
         | 
| 32 | 
            +
                      KAFKA_PORT: 9093
         | 
| 33 | 
            +
                      KAFKA_ZOOKEEPER_CONNECT: localhost:2181
         | 
| 34 | 
            +
                      KAFKA_DELETE_TOPIC_ENABLE: true
         | 
| 35 | 
            +
                  - image: wurstmeister/kafka:2.11-2.0.0
         | 
| 36 | 
            +
                    environment:
         | 
| 37 | 
            +
                      KAFKA_ADVERTISED_HOST_NAME: localhost
         | 
| 38 | 
            +
                      KAFKA_ADVERTISED_PORT: 9094
         | 
| 39 | 
            +
                      KAFKA_PORT: 9094
         | 
| 40 | 
            +
                      KAFKA_ZOOKEEPER_CONNECT: localhost:2181
         | 
| 41 | 
            +
                      KAFKA_DELETE_TOPIC_ENABLE: true
         | 
| 42 | 
            +
                executor: ruby/default
         | 
| 43 | 
            +
                steps:
         | 
| 44 | 
            +
                  - checkout
         | 
| 45 | 
            +
                  - run:
         | 
| 46 | 
            +
                      name: Which bundler?
         | 
| 47 | 
            +
                      command: bundle -v
         | 
| 48 | 
            +
                  - ruby/bundle-install
         | 
| 49 | 
            +
                  - run: bundle exec rspec --pattern='spec/integration/*_spec.rb'
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            workflows:
         | 
| 52 | 
            +
              version: 2
         | 
| 53 | 
            +
              test:
         | 
| 54 | 
            +
                jobs:
         | 
| 55 | 
            +
                  - build
         | 
| 56 | 
            +
                  - integration-tests
         | 
| @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            name: CI
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            on:
         | 
| 4 | 
            +
              push:
         | 
| 5 | 
            +
                branches:
         | 
| 6 | 
            +
                  - '**'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            jobs:
         | 
| 9 | 
            +
              unit-specs:
         | 
| 10 | 
            +
                runs-on: ubuntu-latest
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                strategy:
         | 
| 13 | 
            +
                  matrix:
         | 
| 14 | 
            +
                    ruby-version: ["2.5", "2.6"]
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                steps:
         | 
| 17 | 
            +
                - uses: zendesk/checkout@v2
         | 
| 18 | 
            +
                - name: Set up Ruby
         | 
| 19 | 
            +
                  uses: zendesk/setup-ruby@v1.58.0
         | 
| 20 | 
            +
                  with:
         | 
| 21 | 
            +
                    ruby-version: ${{ matrix.ruby-version }}
         | 
| 22 | 
            +
                    bundler-cache: true
         | 
| 23 | 
            +
                - name: Build and test with RSpec
         | 
| 24 | 
            +
                  run: bundle exec rspec --format documentation --require spec_helper --color --exclude-pattern='spec/integration/*_spec.rb'
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              integration-specs:
         | 
| 27 | 
            +
                runs-on: ubuntu-latest
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                services:
         | 
| 30 | 
            +
                  zookeeper:
         | 
| 31 | 
            +
                    image: confluentinc/cp-zookeeper
         | 
| 32 | 
            +
                    ports:
         | 
| 33 | 
            +
                      - 2181:2181
         | 
| 34 | 
            +
                    env:
         | 
| 35 | 
            +
                      ZOOKEEPER_CLIENT_PORT: 2181
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  kafka:
         | 
| 38 | 
            +
                    image: confluentinc/cp-kafka
         | 
| 39 | 
            +
                    ports:
         | 
| 40 | 
            +
                      - 9092:9092
         | 
| 41 | 
            +
                      - 29092:29092
         | 
| 42 | 
            +
                    options: --health-cmd "kafka-topics --list --bootstrap-server=localhost:9092" --health-interval 10s --health-timeout 5s --health-retries 5
         | 
| 43 | 
            +
                    env:
         | 
| 44 | 
            +
                      KAFKA_BROKER_ID: 1
         | 
| 45 | 
            +
                      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
         | 
| 46 | 
            +
                      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
         | 
| 47 | 
            +
                      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
         | 
| 48 | 
            +
                      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
         | 
| 49 | 
            +
                      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                steps:
         | 
| 52 | 
            +
                - uses: zendesk/checkout@v2
         | 
| 53 | 
            +
                - name: Set up Ruby
         | 
| 54 | 
            +
                  uses: zendesk/setup-ruby@v1.58.0
         | 
| 55 | 
            +
                  with:
         | 
| 56 | 
            +
                    ruby-version: 2.7
         | 
| 57 | 
            +
                    bundler-cache: true
         | 
| 58 | 
            +
                - name: Build and test with RSpec
         | 
| 59 | 
            +
                  env:
         | 
| 60 | 
            +
                    RACECAR_BROKERS: localhost:9092
         | 
| 61 | 
            +
                  run: bundle exec rspec --format documentation --require spec_helper --color spec/integration/*_spec.rb
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -2,10 +2,58 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            ## Unreleased
         | 
| 4 4 |  | 
| 5 | 
            +
            ## racecar v2.2.0
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            * [Racecar::ConsumerSet] **breaking change** `Racecar::ConsumerSet`'s functions `poll` and `batch_pall` expect the max wait values to be given in milliseconds. The defaults were using `config.max_wait_time`, which is in seconds. If you do not directly use `Racecar::ConsumerSet`, or always call its `poll` and `batch_poll` functions by specfiying the max wait time (the first argument), then this breaking change does not affect you. ([#214](https://github.com/zendesk/racecar/pull/214))
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## racecar v2.1.1
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            * [Bugfix] Close RdKafka consumer in ConsumerSet#reset_current_consumer to prevent memory leak (#196)
         | 
| 12 | 
            +
            * [Bugfix] `poll`/`batch_poll` would not retry in edge cases and raise immediately. They still honor the `max_wait_time` setting, but might return no messages instead and only retry on their next call. ([#177](https://github.com/zendesk/racecar/pull/177))
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            ## racecar v2.1.0
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            * Bump rdkafka to 0.8.0 (#191)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            ## racecar v2.0.0
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            * Replace `ruby-kafka` with `rdkafka-ruby` as the low-level library underneath Racecar (#91).
         | 
| 21 | 
            +
            * Fix `max_wait_time` usage (#179).
         | 
| 22 | 
            +
            * Removed config option `sasl_over_ssl`.
         | 
| 23 | 
            +
            * [Racecar::Consumer] Do not pause consuming partitions on exception.
         | 
| 24 | 
            +
            * [Racecar::Consumer] `topic`, `payload` and `key` are mandadory to method `produce`.
         | 
| 25 | 
            +
            * [Racecar::Consumer] `process_batch` retrieves an array of messages instead of batch object.
         | 
| 26 | 
            +
            * [Racecar::Consumer] Remove `offset_retention_time`.
         | 
| 27 | 
            +
            * [Racecar::Consumer] Allow providing `additional_config` for subscriptions.
         | 
| 28 | 
            +
            * [Racecar::Consumer] Provide access to `producer` and `consumer`.
         | 
| 29 | 
            +
            * [Racecar::Consumer] Enforce delivering messages with method `deliver!`.
         | 
| 30 | 
            +
            * [Racecar::Consumer] instead of raising when a partition EOF is reached, the result can be queried through `consumer.last_poll_read_partition_eof?`.
         | 
| 31 | 
            +
            * [Racecar::Config] Remove `offset_retention_time`, `connect_timeout` and `offset_commit_threshold`.
         | 
| 32 | 
            +
            * [Racecar::Config] Pass config to `rdkafka-ruby` via `producer` and `consumer`.
         | 
| 33 | 
            +
            * [Racecar::Config] Replace `max_fetch_queue_size` with `min_message_queue_size`.
         | 
| 34 | 
            +
            * [Racecar::Config] Add `synchronous_commits` to control blocking of `consumer.commit` (default `false`).
         | 
| 35 | 
            +
            * [Racecar::Config] Add `security_protocol` to control protocol between client and broker.
         | 
| 36 | 
            +
            * [Racecar::Config] SSL configuration via `ssl_ca_location`, `ssl_crl_location`, `ssl_keystore_location` and `ssl_keystore_password`.
         | 
| 37 | 
            +
            * [Racecar::Config] SASL configuration via `sasl_mechanism`, `sasl_kerberos_service_name`, `sasl_kerberos_principal`, `sasl_kerberos_kinit_cmd`, `sasl_kerberos_keytab`, `sasl_kerberos_min_time_before_relogin`, `sasl_username` and `sasl_password`.
         | 
| 38 | 
            +
            * [Instrumentation] `produce_message.racecar` sent whenever a produced message is queued. Payload includes `topic`, `key`, `value` and `create_time`.
         | 
| 39 | 
            +
            * [Instrumentation] `acknowledged_message.racecar` send whenever a produced message was successfully received by Kafka. Payload includes `offset` and `partition`, but no message details.
         | 
| 40 | 
            +
            * [Instrumentation] `rdkafka-ruby` does not yet provide instrumentation [rdkafka-ruby#54](https://github.com/appsignal/rdkafka-ruby/issues/54).
         | 
| 41 | 
            +
            * [Instrumentation] if processors define a `statistics_callback`, it will be called once every second for every subscription or producer connection. The first argument will be a Hash, for contents see [librdkafka STATISTICS.md](https://github.com/edenhill/librdkafka/blob/master/STATISTICS.md).
         | 
| 42 | 
            +
            * Add current directory to `$LOAD_PATH` only when `--require` option is used (#117).
         | 
| 43 | 
            +
            * Remove manual heartbeat support, see [Long-running message processing section in README](README.md#long-running-message-processing).
         | 
| 44 | 
            +
            * Rescue exceptions--then log and pass to `on_error`--at the outermost level of `exe/racecar`, so that exceptions raised outside `Cli.run` are not silently discarded (#186).
         | 
| 45 | 
            +
            * When exceptions with a `cause` are logged, recursively log the `cause` detail, separated by `--- Caused by: ---\n`.
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            ## racecar v1.0.0
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            Unchanged from v0.5.0.
         | 
| 50 | 
            +
             | 
| 5 51 | 
             
            ## racecar v0.5.0
         | 
| 6 52 |  | 
| 7 53 | 
             
            * Add support for manually sending heartbeats with `heartbeat` (#105).
         | 
| 8 54 | 
             
            * Allow configuring `sasl_over_ssl`.
         | 
| 55 | 
            +
            * Add current directory to `$LOAD_PATH` only when `--require` option is used (#117).
         | 
| 56 | 
            +
            * Support for `ssl_verify_hostname` in the configuration (#120)
         | 
| 9 57 |  | 
| 10 58 | 
             
            ## racecar v0.4.2
         | 
| 11 59 |  | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | @@ -0,0 +1,69 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: .
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                racecar (2.1.1)
         | 
| 5 | 
            +
                  king_konf (~> 1.0.0)
         | 
| 6 | 
            +
                  rdkafka (~> 0.8.0)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            GEM
         | 
| 9 | 
            +
              remote: https://rubygems.org/
         | 
| 10 | 
            +
              specs:
         | 
| 11 | 
            +
                activesupport (6.0.3.4)
         | 
| 12 | 
            +
                  concurrent-ruby (~> 1.0, >= 1.0.2)
         | 
| 13 | 
            +
                  i18n (>= 0.7, < 2)
         | 
| 14 | 
            +
                  minitest (~> 5.1)
         | 
| 15 | 
            +
                  tzinfo (~> 1.1)
         | 
| 16 | 
            +
                  zeitwerk (~> 2.2, >= 2.2.2)
         | 
| 17 | 
            +
                coderay (1.1.3)
         | 
| 18 | 
            +
                concurrent-ruby (1.1.7)
         | 
| 19 | 
            +
                diff-lcs (1.4.4)
         | 
| 20 | 
            +
                dogstatsd-ruby (4.8.2)
         | 
| 21 | 
            +
                ffi (1.13.1)
         | 
| 22 | 
            +
                i18n (1.8.5)
         | 
| 23 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 24 | 
            +
                king_konf (1.0.0)
         | 
| 25 | 
            +
                method_source (1.0.0)
         | 
| 26 | 
            +
                mini_portile2 (2.5.0)
         | 
| 27 | 
            +
                minitest (5.14.2)
         | 
| 28 | 
            +
                pry (0.13.1)
         | 
| 29 | 
            +
                  coderay (~> 1.1)
         | 
| 30 | 
            +
                  method_source (~> 1.0)
         | 
| 31 | 
            +
                rake (13.0.1)
         | 
| 32 | 
            +
                rdkafka (0.8.1)
         | 
| 33 | 
            +
                  ffi (~> 1.9)
         | 
| 34 | 
            +
                  mini_portile2 (~> 2.1)
         | 
| 35 | 
            +
                  rake (>= 12.3)
         | 
| 36 | 
            +
                rspec (3.10.0)
         | 
| 37 | 
            +
                  rspec-core (~> 3.10.0)
         | 
| 38 | 
            +
                  rspec-expectations (~> 3.10.0)
         | 
| 39 | 
            +
                  rspec-mocks (~> 3.10.0)
         | 
| 40 | 
            +
                rspec-core (3.10.0)
         | 
| 41 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 42 | 
            +
                rspec-expectations (3.10.0)
         | 
| 43 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 44 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 45 | 
            +
                rspec-mocks (3.10.0)
         | 
| 46 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 47 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 48 | 
            +
                rspec-support (3.10.0)
         | 
| 49 | 
            +
                thread_safe (0.3.6)
         | 
| 50 | 
            +
                timecop (0.9.2)
         | 
| 51 | 
            +
                tzinfo (1.2.8)
         | 
| 52 | 
            +
                  thread_safe (~> 0.1)
         | 
| 53 | 
            +
                zeitwerk (2.4.2)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            PLATFORMS
         | 
| 56 | 
            +
              ruby
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            DEPENDENCIES
         | 
| 59 | 
            +
              activesupport (>= 4.0, < 6.1)
         | 
| 60 | 
            +
              bundler (>= 1.13, < 3)
         | 
| 61 | 
            +
              dogstatsd-ruby (>= 4.0.0, < 5.0.0)
         | 
| 62 | 
            +
              pry
         | 
| 63 | 
            +
              racecar!
         | 
| 64 | 
            +
              rake (> 10.0)
         | 
| 65 | 
            +
              rspec (~> 3.0)
         | 
| 66 | 
            +
              timecop
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            BUNDLED WITH
         | 
| 69 | 
            +
               2.1.4
         | 
    
        data/README.md
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            Racecar is a friendly and easy-to-approach Kafka consumer framework. It allows you to write small applications that process messages stored in Kafka topics while optionally integrating with your Rails models.
         | 
| 4 4 |  | 
| 5 | 
            -
            The framework is based on [ruby | 
| 5 | 
            +
            The framework is based on [rdkafka-ruby](https://github.com/appsignal/rdkafka-ruby), which, when used directly, can be a challenge: it's a flexible library with lots of knobs and options. Most users don't need that level of flexibility, though. Racecar provides a simple and intuitive way to build and configure Kafka consumers.
         | 
| 6 6 |  | 
| 7 7 | 
             
            **NOTE:** Racecar requires Kafka 0.10 or higher.
         | 
| 8 8 |  | 
| @@ -19,6 +19,7 @@ The framework is based on [ruby-kafka](https://github.com/zendesk/ruby-kafka), w | |
| 19 19 | 
             
                7. [Handling errors](#handling-errors)
         | 
| 20 20 | 
             
                8. [Logging](#logging)
         | 
| 21 21 | 
             
                9. [Operations](#operations)
         | 
| 22 | 
            +
                10. [Upgrading from v1 to v2](#upgrading-from-v1-to-v2)
         | 
| 22 23 | 
             
            3. [Development](#development)
         | 
| 23 24 | 
             
            4. [Contributing](#contributing)
         | 
| 24 25 | 
             
            5. [Support and Discussion](#support-and-discussion)
         | 
| @@ -49,9 +50,7 @@ This will add a config file in `config/racecar.yml`. | |
| 49 50 |  | 
| 50 51 | 
             
            ## Usage
         | 
| 51 52 |  | 
| 52 | 
            -
            Racecar is built for simplicity of development and operation.  | 
| 53 | 
            -
             | 
| 54 | 
            -
            First, a short introduction to the Kafka consumer concept as well as some basic background on Kafka.
         | 
| 53 | 
            +
            Racecar is built for simplicity of development and operation. First, a short introduction to the Kafka consumer concept as well as some basic background on Kafka.
         | 
| 55 54 |  | 
| 56 55 | 
             
            Kafka stores messages in so-called _partitions_ which are grouped into _topics_. Within a partition, each message gets a unique offset.
         | 
| 57 56 |  | 
| @@ -121,23 +120,23 @@ Note that once the consumer has started, it will commit the offsets it has proce | |
| 121 120 |  | 
| 122 121 | 
             
            #### Processing messages in batches
         | 
| 123 122 |  | 
| 124 | 
            -
            If you want to process whole _batches_ of messages at a time, simply rename your `#process` method to `#process_batch`. The method will now be called with  | 
| 123 | 
            +
            If you want to process whole _batches_ of messages at a time, simply rename your `#process` method to `#process_batch`. The method will now be called with an array of message objects:
         | 
| 125 124 |  | 
| 126 125 | 
             
            ```ruby
         | 
| 127 126 | 
             
            class ArchiveEventsConsumer < Racecar::Consumer
         | 
| 128 127 | 
             
              subscribes_to "events"
         | 
| 129 128 |  | 
| 130 | 
            -
              def process_batch( | 
| 129 | 
            +
              def process_batch(messages)
         | 
| 131 130 | 
             
                file_name = [
         | 
| 132 | 
            -
                   | 
| 133 | 
            -
                   | 
| 134 | 
            -
                   | 
| 135 | 
            -
                   | 
| 131 | 
            +
                  messages.first.topic, # the topic this batch of messages came from.
         | 
| 132 | 
            +
                  messages.first.partition, # the partition this batch of messages came from.
         | 
| 133 | 
            +
                  messages.first.offset, # offset of the first message in the batch.
         | 
| 134 | 
            +
                  messages.last.offset, # offset of the last message in the batch.
         | 
| 136 135 | 
             
                ].join("-")
         | 
| 137 136 |  | 
| 138 137 | 
             
                File.open(file_name, "w") do |file|
         | 
| 139 138 | 
             
                  # the messages in the batch.
         | 
| 140 | 
            -
                   | 
| 139 | 
            +
                  messages.each do |message|
         | 
| 141 140 | 
             
                    file << message.value
         | 
| 142 141 | 
             
                  end
         | 
| 143 142 | 
             
                end
         | 
| @@ -155,23 +154,13 @@ Any headers set on the message will be available when consuming the message: | |
| 155 154 | 
             
            message.headers #=> { "Header-A" => 42, ... }
         | 
| 156 155 | 
             
            ```
         | 
| 157 156 |  | 
| 158 | 
            -
            ####  | 
| 157 | 
            +
            #### Long-running message processing
         | 
| 159 158 |  | 
| 160 | 
            -
            In order to avoid your consumer being kicked out of its group during long-running message processing operations,  | 
| 159 | 
            +
            In order to avoid your consumer being kicked out of its group during long-running message processing operations, you'll need to let Kafka regularly know that the consumer is still healthy. There's two mechanisms in place to ensure that:
         | 
| 161 160 |  | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
            ```ruby
         | 
| 165 | 
            -
            def process(message)
         | 
| 166 | 
            -
              long_running_op_one(message)
         | 
| 167 | 
            -
             | 
| 168 | 
            -
              # Signals back to Kafka that we're still alive!
         | 
| 169 | 
            -
              heartbeat
         | 
| 170 | 
            -
             | 
| 171 | 
            -
              long_running_op_two(message)
         | 
| 172 | 
            -
            end
         | 
| 173 | 
            -
            ```
         | 
| 161 | 
            +
            *Heartbeats:* They are automatically sent in the background and ensure the broker can still talk to the consumer. This will detect network splits, ungraceful shutdowns, etc.
         | 
| 174 162 |  | 
| 163 | 
            +
            *Message Fetch Interval:* Kafka expects the consumer to query for new messages within this time limit. This will detect situations with slow IO or the consumer being stuck in an infinite loop without making actual progress. This limit applies to a whole batch if you do batch processing. Use `max_poll_interval` to increase the default 5 minute timeout, or reduce batching with `fetch_messages`.
         | 
| 175 164 |  | 
| 176 165 | 
             
            #### Tearing down resources when stopping
         | 
| 177 166 |  | 
| @@ -222,18 +211,20 @@ class GeoCodingConsumer < Racecar::Consumer | |
| 222 211 |  | 
| 223 212 | 
             
                # The `produce` method enqueues a message to be delivered after #process
         | 
| 224 213 | 
             
                # returns. It won't actually deliver the message.
         | 
| 225 | 
            -
                produce(JSON.dump(pageview), topic: "pageviews-with-country")
         | 
| 214 | 
            +
                produce(JSON.dump(pageview), topic: "pageviews-with-country", key: pageview["id"])
         | 
| 226 215 | 
             
              end
         | 
| 227 216 | 
             
            end
         | 
| 228 217 | 
             
            ```
         | 
| 229 218 |  | 
| 219 | 
            +
            The `deliver!` method can be used to block until the broker received all queued published messages (according to the publisher ack settings). This will automatically being called in the shutdown procedure of a consumer.
         | 
| 220 | 
            +
             | 
| 230 221 | 
             
            You can set message headers by passing a `headers:` option with a Hash of headers.
         | 
| 231 222 |  | 
| 232 223 | 
             
            ### Configuration
         | 
| 233 224 |  | 
| 234 225 | 
             
            Racecar provides a flexible way to configure your consumer in a way that feels at home in a Rails application. If you haven't already, run `bundle exec rails generate racecar:install` in order to generate a config file. You'll get a separate section for each Rails environment, with the common configuration values in a shared `common` section.
         | 
| 235 226 |  | 
| 236 | 
            -
            **Note:** many of these configuration keys correspond directly to similarly named concepts in [ruby | 
| 227 | 
            +
            **Note:** many of these configuration keys correspond directly to similarly named concepts in [rdkafka-ruby](https://github.com/appsignal/rdkafka-ruby); for more details on low-level operations, read that project's documentation.
         | 
| 237 228 |  | 
| 238 229 | 
             
            It's also possible to configure Racecar using environment variables. For any given configuration key, there should be a corresponding environment variable with the prefix `RACECAR_`, in upper case. For instance, in order to configure the client id, set `RACECAR_CLIENT_ID=some-id` in the process in which the Racecar consumer is launched. You can set `brokers` by passing a comma-separated list, e.g. `RACECAR_BROKERS=kafka1:9092,kafka2:9092,kafka3:9092`.
         | 
| 239 230 |  | 
| @@ -263,8 +254,6 @@ end | |
| 263 254 | 
             
            The consumers will checkpoint their positions from time to time in order to be able to recover from failures. This is called _committing offsets_, since it's done by tracking the offset reached in each partition being processed, and committing those offset numbers to the Kafka offset storage API. If you can tolerate more double-processing after a failure, you can increase the interval between commits in order to better performance. You can also do the opposite if you prefer less chance of double-processing.
         | 
| 264 255 |  | 
| 265 256 | 
             
            * `offset_commit_interval` – How often to save the consumer's position in Kafka. Default is every 10 seconds.
         | 
| 266 | 
            -
            * `offset_commit_threshold` – How many messages to process before forcing a checkpoint. Default is 0, which means there's no limit. Setting this to e.g. 100 makes the consumer stop every 100 messages to checkpoint its position.
         | 
| 267 | 
            -
            * `offset_retention_time` - How long committed offsets will be retained. Defaults to the broker setting.
         | 
| 268 257 |  | 
| 269 258 | 
             
            #### Timeouts & intervals
         | 
| 270 259 |  | 
| @@ -272,8 +261,9 @@ All timeouts are defined in number of seconds. | |
| 272 261 |  | 
| 273 262 | 
             
            * `session_timeout` – The idle timeout after which a consumer is kicked out of the group. Consumers must send heartbeats with at least this frequency.
         | 
| 274 263 | 
             
            * `heartbeat_interval` – How often to send a heartbeat message to Kafka.
         | 
| 275 | 
            -
            * ` | 
| 276 | 
            -
            * ` | 
| 264 | 
            +
            * `max_poll_interval` – The maximum time between two message fetches before the consumer is kicked out of the group. Put differently, your (batch) processing must finish earlier than this.
         | 
| 265 | 
            +
            * `pause_timeout` – How long to pause a partition for if the consumer raises an exception while processing a message. Default is to pause for 10 seconds. Set this to `0` in order to disable automatic pausing of partitions or to `-1` to pause indefinitely.
         | 
| 266 | 
            +
            * `pause_with_exponential_backoff` – Set to `true` if you want to double the `pause_timeout` on each consecutive failure of a particular partition.
         | 
| 277 267 | 
             
            * `socket_timeout` – How long to wait when trying to communicate with a Kafka broker. Default is 30 seconds.
         | 
| 278 268 | 
             
            * `max_wait_time` – How long to allow the Kafka brokers to wait before returning messages. A higher number means larger batches, at the cost of higher latency. Default is 1 second.
         | 
| 279 269 |  | 
| @@ -281,40 +271,37 @@ All timeouts are defined in number of seconds. | |
| 281 271 |  | 
| 282 272 | 
             
            Kafka is _really_ good at throwing data at consumers, so you may want to tune these variables in order to avoid ballooning your process' memory or saturating your network capacity.
         | 
| 283 273 |  | 
| 284 | 
            -
            Racecar uses ruby- | 
| 274 | 
            +
            Racecar uses [rdkafka-ruby](https://github.com/appsignal/rdkafka-ruby) under the hood, which fetches messages from the Kafka brokers in a background thread. This thread pushes fetch responses, possible containing messages from many partitions, into a queue that is read by the processing thread (AKA your code). The main way to control the fetcher thread is to control the size of those responses and the size of the queue.
         | 
| 285 275 |  | 
| 286 | 
            -
            * `max_bytes` —  | 
| 287 | 
            -
            * ` | 
| 276 | 
            +
            * `max_bytes` — Maximum amount of data the broker shall return for a Fetch request.
         | 
| 277 | 
            +
            * `min_message_queue_size` — The minimum number of messages in the local consumer queue.
         | 
| 288 278 |  | 
| 289 | 
            -
            The memory usage limit is roughly estimated as `max_bytes *  | 
| 279 | 
            +
            The memory usage limit is roughly estimated as `max_bytes * min_message_queue_size`, plus whatever your application uses.
         | 
| 290 280 |  | 
| 291 281 | 
             
            #### SSL encryption, authentication & authorization
         | 
| 292 282 |  | 
| 293 | 
            -
            * ` | 
| 294 | 
            -
            * ` | 
| 295 | 
            -
            * ` | 
| 296 | 
            -
            * ` | 
| 283 | 
            +
            * `security_protocol` – Protocol used to communicate with brokers (`:ssl`)
         | 
| 284 | 
            +
            * `ssl_ca_location` – File or directory path to CA certificate(s) for verifying the broker's key
         | 
| 285 | 
            +
            * `ssl_crl_location` – Path to CRL for verifying broker's certificate validity
         | 
| 286 | 
            +
            * `ssl_keystore_location` – Path to client's keystore (PKCS#12) used for authentication
         | 
| 287 | 
            +
            * `ssl_keystore_password` – Client's keystore (PKCS#12) password
         | 
| 288 | 
            +
            * `ssl_certificate_location` – Path to the certificate
         | 
| 289 | 
            +
            * `ssl_key_location` – Path to client's certificate used for authentication
         | 
| 290 | 
            +
            * `ssl_key_password` – Client's certificate password
         | 
| 297 291 |  | 
| 298 292 | 
             
            #### SASL encryption, authentication & authorization
         | 
| 299 293 |  | 
| 300 | 
            -
            Racecar has support for using SASL to authenticate clients using either the GSSAPI or PLAIN mechanism.
         | 
| 294 | 
            +
            Racecar has support for using SASL to authenticate clients using either the GSSAPI or PLAIN mechanism either via plaintext or SSL connection.
         | 
| 301 295 |  | 
| 302 | 
            -
             | 
| 296 | 
            +
            * `security_protocol` – Protocol used to communicate with brokers (`:sasl_plaintext` `:sasl_ssl`)
         | 
| 297 | 
            +
            * `sasl_mechanism` – SASL mechanism to use for authentication (`GSSAPI` `PLAIN` `SCRAM-SHA-256` `SCRAM-SHA-512`)
         | 
| 303 298 |  | 
| 304 | 
            -
            * ` | 
| 305 | 
            -
            * ` | 
| 306 | 
            -
             | 
| 307 | 
            -
             | 
| 308 | 
            -
             | 
| 309 | 
            -
            * ` | 
| 310 | 
            -
            * `sasl_plain_username` – The username used to authenticate.
         | 
| 311 | 
            -
            * `sasl_plain_password` – The password used to authenticate.
         | 
| 312 | 
            -
             | 
| 313 | 
            -
            If using SCRAM:
         | 
| 314 | 
            -
             | 
| 315 | 
            -
            * `sasl_scram_username` – The username used to authenticate.
         | 
| 316 | 
            -
            * `sasl_scram_password` – The password used to authenticate.
         | 
| 317 | 
            -
            * `sasl_scram_mechanism` – The SCRAM mechanism to use, either `sha256` or `sha512`.
         | 
| 299 | 
            +
            * `sasl_kerberos_principal` – This client's Kerberos principal name
         | 
| 300 | 
            +
            * `sasl_kerberos_kinit_cmd` – Full kerberos kinit command string, `%{config.prop.name}` is replaced by corresponding config object value, `%{broker.name}` returns the broker's hostname
         | 
| 301 | 
            +
            * `sasl_kerberos_keytab` – Path to Kerberos keytab file. Uses system default if not set
         | 
| 302 | 
            +
            * `sasl_kerberos_min_time_before_relogin` – Minimum time in milliseconds between key refresh attempts
         | 
| 303 | 
            +
            * `sasl_username` – SASL username for use with the PLAIN and SASL-SCRAM-.. mechanism
         | 
| 304 | 
            +
            * `sasl_password` – SASL password for use with the PLAIN and SASL-SCRAM-.. mechanism
         | 
| 318 305 |  | 
| 319 306 | 
             
            #### Producing messages
         | 
| 320 307 |  | 
| @@ -324,7 +311,7 @@ These settings are related to consumers that _produce messages to Kafka_. | |
| 324 311 |  | 
| 325 312 | 
             
            #### Datadog monitoring
         | 
| 326 313 |  | 
| 327 | 
            -
            Racecar supports  | 
| 314 | 
            +
            Racecar supports [Datadog](https://www.datadoghq.com/) monitoring integration. If you're running a normal Datadog agent on your host, you just need to set `datadog_enabled` to `true`, as the rest of the settings come with sane defaults.
         | 
| 328 315 |  | 
| 329 316 | 
             
            * `datadog_enabled` – Whether Datadog monitoring is enabled (defaults to `false`).
         | 
| 330 317 | 
             
            * `datadog_host` – The host running the Datadog agent.
         | 
| @@ -332,6 +319,9 @@ Racecar supports configuring ruby-kafka's [Datadog](https://www.datadoghq.com/) | |
| 332 319 | 
             
            * `datadog_namespace` – The namespace to use for Datadog metrics.
         | 
| 333 320 | 
             
            * `datadog_tags` – Tags that should always be set on Datadog metrics.
         | 
| 334 321 |  | 
| 322 | 
            +
            #### Consumers Without Rails ####
         | 
| 323 | 
            +
             | 
| 324 | 
            +
            By default, if Rails is detected, it will be automatically started when the consumer is started. There are cases where you might not want or need Rails. You can pass the `--without-rails` option when starting the consumer and Rails won't be started.
         | 
| 335 325 |  | 
| 336 326 | 
             
            ### Testing consumers
         | 
| 337 327 |  | 
| @@ -474,7 +464,7 @@ Racecar.config.on_error do |exception, info| | |
| 474 464 | 
             
            end
         | 
| 475 465 | 
             
            ```
         | 
| 476 466 |  | 
| 477 | 
            -
            It is highly recommended that you set up an error handler.
         | 
| 467 | 
            +
            It is highly recommended that you set up an error handler. Please note that the `info` object contains different keys and values depending on whether you are using `process` or `process_batch`. See the `instrumentation_payload` object in the `process` and `process_batch` methods in the `Runner` class for the complete list.
         | 
| 478 468 |  | 
| 479 469 |  | 
| 480 470 | 
             
            ### Logging
         | 
| @@ -491,10 +481,17 @@ In order to gracefully shut down a Racecar consumer process, send it the `SIGTER | |
| 491 481 | 
             
            In order to introspect the configuration of a consumer process, send it the `SIGUSR1` signal. This will make Racecar print its configuration to the standard error file descriptor associated with the consumer process, so you'll need to know where that is written to.
         | 
| 492 482 |  | 
| 493 483 |  | 
| 484 | 
            +
            ### Upgrading from v1 to v2
         | 
| 485 | 
            +
             | 
| 486 | 
            +
            In order to safely upgrade from Racecar v1 to v2, you need to completely shut down your consumer group before starting it up again with the v2 Racecar dependency. In general, you should avoid rolling deploys for consumers groups, so it is likely the case that this will just work for you, but it's a good idea to check first.
         | 
| 487 | 
            +
             | 
| 488 | 
            +
             | 
| 494 489 | 
             
            ## Development
         | 
| 495 490 |  | 
| 496 491 | 
             
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
| 497 492 |  | 
| 493 | 
            +
            The integration tests run against a Kafka instance that is not automatically started from within `rspec`. You can set one up using the provided `docker-compose.yml` by running `docker-compose up`.
         | 
| 494 | 
            +
             | 
| 498 495 |  | 
| 499 496 | 
             
            ## Contributing
         | 
| 500 497 |  | 
| @@ -503,9 +500,9 @@ Bug reports and pull requests are welcome on [GitHub](https://github.com/zendesk | |
| 503 500 |  | 
| 504 501 | 
             
            ## Support and Discussion
         | 
| 505 502 |  | 
| 506 | 
            -
            If you've discovered a bug, please file a [Github issue](https://github.com/zendesk/racecar/issues/new), and make sure to include all the relevant information, including the version of Racecar, ruby | 
| 503 | 
            +
            If you've discovered a bug, please file a [Github issue](https://github.com/zendesk/racecar/issues/new), and make sure to include all the relevant information, including the version of Racecar, rdkafka-ruby, and Kafka that you're using.
         | 
| 507 504 |  | 
| 508 | 
            -
            If you have other questions, or would like to discuss best practises, how to contribute to the project,  | 
| 505 | 
            +
            If you have other questions, or would like to discuss best practises, or how to contribute to the project, [join our Slack team](https://ruby-kafka-slack.herokuapp.com/)!
         | 
| 509 506 |  | 
| 510 507 |  | 
| 511 508 | 
             
            ## Copyright and license
         |