delivery_boy 1.3.1 → 2.0.0.alpha.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7248183554e5a0d0bc54b355fe18595ffa6e3cbb6cc240c13025d3d15f9f1768
4
- data.tar.gz: 2a58d4099652cb784853169a9fa1569c3d2c1902d1523a91d0fffad20467a235
3
+ metadata.gz: a4dac7da9e416e7c55878674f91006d43b73811e27b1aa05897604d48c6e3162
4
+ data.tar.gz: b5536e1e66d7c8882fe6452b552f50f2fa4e37846870bea0c6b6f5ceef399028
5
5
  SHA512:
6
- metadata.gz: c4b00f742af460bcc6f76b0c04b54352fc370156a8a80c7a7f0a53915764f93195c804689a0782b267d42c534a2657e78c003cd0fb56cd016fd162bdf3c03622
7
- data.tar.gz: 86844e67ddab037b4cb69cc953f19b1e9b3576db7dd8b0815b26e86f0874994ac830f8d1ee67b14dc21e7ad272e25e0d4bdb6ab5c74a50b40a35815c2f70f5da
6
+ metadata.gz: 8390928820e66c27e3ec762344df31d0e4101831e0f1cca21b2289939fbc23cad4f554b17314eb7f92d48e7f3bd1b6d90ebfceac3e3b41065dbabacf3f2aa0b6
7
+ data.tar.gz: 2bf809365bd9f693cf1dd03f61e6cb37c5c43682087ecc013cd0626d558a83bdc04b4dd4b065dc6a9e0170479dc192f2b26f56cc3501ce77aa820b351dddb817
@@ -0,0 +1,4 @@
1
+ # CODEOWNERS file
2
+ # This file defines who should review code changes in this repository.
3
+
4
+ * @zendesk/core-gem-owners
@@ -25,11 +25,6 @@ jobs:
25
25
  ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4']
26
26
 
27
27
  steps:
28
- - name: Run Confluent Platform (Confluent Server)
29
- uses: zendesk/cp-all-in-one-action@v0.2.1
30
- with:
31
- service: broker
32
-
33
28
  - uses: actions/checkout@v4
34
29
 
35
30
  - name: Set up Ruby
@@ -38,10 +33,17 @@ jobs:
38
33
  ruby-version: ${{ matrix.ruby-version }}
39
34
  bundler-cache: true # runs 'bundle install' and caches installed gems automatically
40
35
 
41
- - name: Wait for broker to boot
42
- run: 'while ! nc -z localhost 9092; do echo -n "."; sleep 0.1; done'
43
-
44
36
  - name: Run tests
45
37
  run: bundle exec rake
46
- env:
47
- DELIVERY_BOY_BROKERS: localhost:9092
38
+
39
+ lint:
40
+ runs-on: ubuntu-latest
41
+ steps:
42
+ - uses: actions/checkout@v5
43
+
44
+ - name: Set up Ruby
45
+ uses: ruby/setup-ruby@v1
46
+ with:
47
+ ruby-version: ruby
48
+ bundler-cache: true
49
+ - run: bundle exec rake standard
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
- --format documentation
1
+ --order rand
2
2
  --color
data/.standard.yml ADDED
@@ -0,0 +1 @@
1
+ ruby_version: 2.6
data/CHANGELOG CHANGED
@@ -1,6 +1,55 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## Unreleased (v2.0.0)
4
+
5
+ ### Migration to librdkafka
6
+
7
+ * Migrated from ruby-kafka to rdkafka (librdkafka) for improved performance and stability
8
+
9
+ ### New Features
10
+
11
+ * PLAIN and SCRAM-SHA-256/512 SASL authentication now fully functional with librdkafka
12
+ * Added `sasl_username` and `sasl_password` as consolidated config options (work for both PLAIN and SCRAM)
13
+ * Added automatic `security.protocol` detection (PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL)
14
+ * Backward compatible SASL configuration - existing mechanism-specific options (sasl_plain_username, sasl_scram_username) continue to work
15
+ * OAUTHBEARER authentication via OIDC configuration (librdkafka handles token refresh automatically)
16
+
17
+ ### Breaking Changes & Known Limitations
18
+
19
+ * **AWS MSK IAM authentication is no longer supported** (librdkafka limitation)
20
+ - Alternative 1: Use AWS MSK SCRAM-SHA-512 authentication (recommended)
21
+ - Alternative 2: Use mTLS (mutual TLS) with client certificates
22
+ * **OAUTHBEARER authentication changed from callback-based to OIDC configuration**
23
+ - `sasl_oauth_token_provider` is no longer supported
24
+ - Use new OIDC config options instead: `sasl_oauthbearer_method`, `sasl_oauthbearer_client_id`, `sasl_oauthbearer_client_secret`, `sasl_oauthbearer_token_endpoint_url`
25
+ - librdkafka handles token refresh automatically (no custom code needed)
26
+ * `sasl_plain_authzid` is not supported by librdkafka and will be ignored with a warning
27
+ * `compression_threshold` is no longer supported - librdkafka applies compression automatically to all batches when `compression_codec` is set
28
+
29
+ ### Config options no longer used
30
+
31
+ The following config options are silently ignored (no error, but no effect):
32
+ * `max_queue_size` - rdkafka manages its own internal queue
33
+ * `ssl_ca_certs_from_system` - no librdkafka equivalent
34
+ * `ssl_verify_hostname` - not mapped to librdkafka
35
+ * `sasl_scram_mechanism` - use `sasl_mechanism` instead
36
+ * `log_level` - rdkafka has its own logging configuration
37
+
38
+ ### Datadog Integration
39
+
40
+ * Datadog metrics continue to work with the same metric names as before
41
+ * Now uses `DeliveryBoy::Datadog` instead of `Kafka::Datadog`
42
+ * Instrumentation is built on top of ActiveSupport::Notifications
43
+ * Some metrics are no longer available due to rdkafka's different architecture:
44
+ - `producer.buffer.fill_ratio` / `producer.buffer.fill_percentage`
45
+ - `producer.deliver.attempts`
46
+ - `producer.ack.delay`
47
+ - `async_producer.queue.fill_ratio`
48
+
49
+ ### Other Changes
50
+
51
+ * `compression_codec` in the `DeliveryBoy::Config` is now coerces its value into
52
+ a symbol if the value is present.
4
53
 
5
54
  ## v1.3.1
6
55
 
data/Gemfile CHANGED
@@ -4,5 +4,11 @@ gemspec
4
4
 
5
5
  gem "base64"
6
6
  gem "bigdecimal"
7
+ gem "debug"
8
+ gem "logger"
7
9
  gem "rake", "~> 13.0"
8
10
  gem "rspec", "~> 3.0"
11
+ gem "standard", "~> 1.51.1" if RUBY_VERSION > "3.0"
12
+ gem "testcontainers-kafka", github: "testcontainers/testcontainers-ruby"
13
+ gem "activesupport"
14
+ gem "dogstatsd-ruby"
data/README.md CHANGED
@@ -172,7 +172,7 @@ The codec used to compress messages. Must be either `snappy` or `gzip`.
172
172
 
173
173
  ##### `compression_threshold`
174
174
 
175
- The minimum number of messages that must be buffered before compression is attempted. By default only one message is required. Only relevant if `compression_codec` is set.
175
+ **Deprecated:** This setting has no effect with librdkafka. Compression is applied automatically to all batches when `compression_codec` is set.
176
176
 
177
177
  #### Network
178
178
 
@@ -226,88 +226,136 @@ The password required to read the ssl_client_cert_key. Must be used in combinati
226
226
 
227
227
  #### SASL Authentication and authorization
228
228
 
229
- See [ruby-kafka](https://github.com/zendesk/ruby-kafka#authentication-using-sasl) for more information.
229
+ DeliveryBoy supports SASL authentication with multiple mechanisms.
230
230
 
231
- Use it through `GSSAPI`, `PLAIN` _or_ `OAUTHBEARER`.
231
+ ##### GSSAPI (Kerberos)
232
232
 
233
- ##### `sasl_gssapi_principal`
233
+ ###### `sasl_gssapi_principal`
234
234
 
235
235
  The GSSAPI principal.
236
236
 
237
- ##### `sasl_gssapi_keytab`
237
+ ###### `sasl_gssapi_keytab`
238
238
 
239
239
  Optional GSSAPI keytab.
240
240
 
241
- ##### `sasl_plain_authzid`
241
+ **Example:**
242
242
 
243
- The authorization identity to use.
243
+ ```ruby
244
+ DeliveryBoy.configure do |config|
245
+ config.sasl_mechanism = "GSSAPI"
246
+ config.sasl_gssapi_principal = "kafka/hostname@REALM"
247
+ config.sasl_gssapi_keytab = "/path/to/keytab"
248
+ end
249
+ ```
250
+
251
+ ##### PLAIN Authentication
252
+
253
+ ###### `sasl_plain_username`
254
+
255
+ The username used to authenticate (legacy option).
244
256
 
245
- ##### `sasl_plain_username`
257
+ ###### `sasl_plain_password`
246
258
 
247
- The username used to authenticate.
259
+ The password used to authenticate (legacy option).
248
260
 
249
- ##### `sasl_plain_password`
261
+ ###### `sasl_username`
250
262
 
251
- The password used to authenticate.
263
+ The username used to authenticate (new consolidated option, works for both PLAIN and SCRAM).
252
264
 
253
- ##### `sasl_oauth_token_provider`
265
+ ###### `sasl_password`
254
266
 
255
- A instance of a class which implements the `token` method.
256
- As described in [ruby-kafka](https://github.com/zendesk/ruby-kafka/tree/c3e90bc355fad1e27b9af1048966ff08d3d5735b#oauthbearer)
267
+ The password used to authenticate (new consolidated option, works for both PLAIN and SCRAM).
268
+
269
+ **Example:**
257
270
 
258
271
  ```ruby
259
- class TokenProvider
260
- def token
261
- "oauth-token"
262
- end
272
+ DeliveryBoy.configure do |config|
273
+ config.sasl_mechanism = "PLAIN"
274
+ # You can use either the new consolidated options:
275
+ config.sasl_username = "your-username"
276
+ config.sasl_password = "your-password"
277
+ # Or the legacy mechanism-specific options:
278
+ # config.sasl_plain_username = "your-username"
279
+ # config.sasl_plain_password = "your-password"
263
280
  end
281
+ ```
282
+
283
+ ##### SCRAM Authentication
284
+
285
+ Supports SCRAM-SHA-256 and SCRAM-SHA-512 mechanisms.
286
+
287
+ ###### `sasl_scram_username`
264
288
 
289
+ The username used to authenticate (legacy option).
290
+
291
+ ###### `sasl_scram_password`
292
+
293
+ The password used to authenticate (legacy option).
294
+
295
+ **Example:**
296
+
297
+ ```ruby
265
298
  DeliveryBoy.configure do |config|
266
- config.sasl_oauth_token_provider = TokenProvider.new
267
- config.ssl_ca_certs_from_system = true
299
+ config.sasl_mechanism = "SCRAM-SHA-256" # or "SCRAM-SHA-512"
300
+ # You can use either the new consolidated options:
301
+ config.sasl_username = "your-username"
302
+ config.sasl_password = "your-password"
303
+ # Or the legacy mechanism-specific options:
304
+ # config.sasl_scram_username = "your-username"
305
+ # config.sasl_scram_password = "your-password"
268
306
  end
269
307
  ```
270
308
 
271
- #### AWS MSK IAM Authentication and Authorization
309
+ ##### OAUTHBEARER (OIDC)
310
+
311
+ OAUTHBEARER authentication is supported via OIDC configuration. librdkafka handles token acquisition and refresh automatically.
312
+
313
+ ###### `sasl_oauthbearer_method`
272
314
 
273
- ##### sasl_aws_msk_iam_access_key_id
315
+ Set to `"oidc"` to enable OIDC-based OAUTHBEARER authentication.
274
316
 
275
- The AWS IAM access key. Required.
317
+ ###### `sasl_oauthbearer_client_id`
276
318
 
277
- ##### sasl_aws_msk_iam_secret_key_id
319
+ The OAuth client ID for your application.
278
320
 
279
- The AWS IAM secret access key. Required.
321
+ ###### `sasl_oauthbearer_client_secret`
280
322
 
281
- ##### sasl_aws_msk_iam_aws_region
323
+ The OAuth client secret for your application.
282
324
 
283
- The AWS region. Required.
325
+ ###### `sasl_oauthbearer_token_endpoint_url`
284
326
 
285
- ##### sasl_aws_msk_iam_session_token
327
+ The URL of the OAuth token endpoint (e.g., `https://auth.example.com/oauth/token`).
286
328
 
287
- The session token. This value can be optional.
329
+ ###### `sasl_oauthbearer_scope` (optional)
288
330
 
289
- ###### Examples
331
+ OAuth scope to request.
290
332
 
291
- Using a role arn and web identity token to generate temporary credentials:
333
+ ###### `sasl_oauthbearer_extensions` (optional)
334
+
335
+ Additional SASL extensions as comma-separated key=value pairs.
292
336
 
293
337
  ```ruby
294
- require "aws-sdk-core"
295
- require "delivery_boy"
296
-
297
- role = Aws::AssumeRoleWebIdentityCredentials.new(
298
- role_arn: ENV["AWS_ROLE_ARN"],
299
- web_identity_token_file: ENV["AWS_WEB_IDENTITY_TOKEN_FILE"]
300
- )
301
-
302
- DeliveryBoy.configure do |c|
303
- c.sasl_aws_msk_iam_access_key_id = role.credentials.access_key_id
304
- c.sasl_aws_msk_iam_secret_key_id = role.credentials.secret_access_key
305
- c.sasl_aws_msk_iam_session_token = role.credentials.session_token
306
- c.sasl_aws_msk_iam_aws_region = ENV["AWS_REGION"]
307
- c.ssl_ca_certs_from_system = true
338
+ DeliveryBoy.configure do |config|
339
+ config.sasl_mechanism = "OAUTHBEARER"
340
+ config.sasl_oauthbearer_method = "oidc"
341
+ config.sasl_oauthbearer_client_id = "your-client-id"
342
+ config.sasl_oauthbearer_client_secret = "your-client-secret"
343
+ config.sasl_oauthbearer_token_endpoint_url = "https://auth.example.com/oauth/token"
344
+ # Optional:
345
+ # config.sasl_oauthbearer_scope = "kafka"
308
346
  end
309
347
  ```
310
348
 
349
+ **Note:** The legacy `sasl_oauth_token_provider` callback is no longer supported. Use OIDC configuration instead.
350
+
351
+ #### AWS MSK IAM Authentication
352
+
353
+ **Note:** AWS MSK IAM authentication is not supported by librdkafka.
354
+
355
+ **Recommended alternatives:**
356
+ 1. **Use AWS MSK SCRAM authentication** - Create SCRAM credentials in AWS Secrets Manager and use SCRAM-SHA-512
357
+ 2. **Use mTLS** - Configure mutual TLS with client certificates
358
+
311
359
  ### Testing
312
360
 
313
361
  DeliveryBoy provides a test mode out of the box. When this mode is enabled, messages will be stored in memory rather than being sent to Kafka. If you use RSpec, enabling test mode is as easy as adding this to your spec helper:
data/Rakefile CHANGED
@@ -1,7 +1,12 @@
1
1
  require "bundler/setup"
2
2
  require "bundler/gem_tasks"
3
+ begin
4
+ require "standard/rake"
5
+ rescue LoadError
6
+ :noop
7
+ end
3
8
  require "rspec/core/rake_task"
4
9
 
5
10
  RSpec::Core::RakeTask.new(:spec)
6
11
 
7
- task :default => :spec
12
+ task default: :spec
data/SECURITY.md ADDED
@@ -0,0 +1,5 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ Please report security vulnerabilities by e-mailing: security@zendesk.com
data/delivery_boy.gemspec CHANGED
@@ -1,25 +1,24 @@
1
- # coding: utf-8
2
1
  lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require "delivery_boy/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "delivery_boy"
8
- spec.version = DeliveryBoy::VERSION
9
- spec.authors = ["Daniel Schierbeck"]
10
- spec.email = ["daniel.schierbeck@gmail.com"]
6
+ spec.name = "delivery_boy"
7
+ spec.version = DeliveryBoy::VERSION
8
+ spec.authors = ["Daniel Schierbeck"]
9
+ spec.email = ["daniel.schierbeck@gmail.com"]
11
10
 
12
- spec.summary = "A simple way to produce messages to Kafka from Ruby applications"
13
- spec.description = "A simple way to produce messages to Kafka from Ruby applications"
14
- spec.homepage = "https://github.com/zendesk/delivery_boy"
15
- spec.license = "Apache License Version 2.0"
11
+ spec.summary = "A simple way to produce messages to Kafka from Ruby applications"
12
+ spec.description = "A simple way to produce messages to Kafka from Ruby applications"
13
+ spec.homepage = "https://github.com/zendesk/delivery_boy"
14
+ spec.license = "Apache License Version 2.0"
16
15
 
17
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
17
  f.match(%r{^(test|spec|features)/})
19
18
  end
20
19
 
21
20
  spec.require_paths = ["lib"]
22
21
 
23
- spec.add_dependency "ruby-kafka", "~> 1.5"
24
- spec.add_dependency "king_konf", "~> 1.0"
22
+ spec.add_runtime_dependency "king_konf", "~> 1.0"
23
+ spec.add_runtime_dependency "rdkafka", "> 0.11"
25
24
  end
@@ -4,15 +4,67 @@ module DeliveryBoy
4
4
  class Config < KingKonf::Config
5
5
  env_prefix :delivery_boy
6
6
 
7
+ def connection_timeout_ms
8
+ connect_timeout * 1000
9
+ end
10
+
11
+ def socket_timeout_ms
12
+ socket_timeout * 1000
13
+ end
14
+
15
+ def transactional_timeout_ms
16
+ transactional_timeout * 1000
17
+ end
18
+
19
+ def max_buffer_kbytesize
20
+ max_buffer_bytesize / 1024
21
+ end
22
+
23
+ def delivery_interval_ms
24
+ delivery_interval * 1000
25
+ end
26
+
27
+ def ack_timeout_ms
28
+ ack_timeout * 1000
29
+ end
30
+
31
+ def retry_backoff_ms
32
+ retry_backoff * 1000
33
+ end
34
+
35
+ def sasl_enabled?
36
+ return false unless sasl_mechanism && !sasl_mechanism.empty?
37
+ sasl_mechanism.upcase != "GSSAPI"
38
+ end
39
+
40
+ def validate_aws_msk_iam!
41
+ if sasl_aws_msk_iam_access_key_id || sasl_aws_msk_iam_secret_key_id || sasl_aws_msk_iam_aws_region
42
+ raise ConfigError, <<~ERROR
43
+ AWS MSK IAM authentication is not supported by librdkafka.
44
+
45
+ Alternatives:
46
+ 1. Use AWS MSK SCRAM-SHA-512 authentication (recommended)
47
+ - Create SCRAM credentials in AWS Secrets Manager
48
+ - Set sasl_mechanism = "SCRAM-SHA-512"
49
+ - Set sasl_username and sasl_password
50
+
51
+ 2. Use mTLS (mutual TLS) with client certificates
52
+ - Configure ssl_client_cert and ssl_client_cert_key
53
+
54
+ See migration guide: https://github.com/zendesk/delivery_boy/blob/master/MIGRATION.md#aws-msk-iam
55
+ ERROR
56
+ end
57
+ end
58
+
7
59
  # Basic
8
60
  list :brokers, items: :string, sep: ",", default: ["localhost:9092"]
9
61
  string :client_id, default: "delivery_boy"
10
62
  string :log_level, default: nil
11
63
 
12
- # Buffering
64
+ # Buffering (defaults match librdkafka defaults to avoid queue overflow at high throughput)
13
65
  integer :max_buffer_bytesize, default: 10_000_000
14
- integer :max_buffer_size, default: 1000
15
- integer :max_queue_size, default: 1000
66
+ integer :max_buffer_size, default: 100_000
67
+ integer :max_queue_size, default: 100_000
16
68
 
17
69
  # Network timeouts
18
70
  integer :connect_timeout, default: 10
@@ -27,11 +79,12 @@ module DeliveryBoy
27
79
  integer :retry_backoff, default: 1
28
80
  boolean :idempotent, default: false
29
81
  boolean :transactional, default: false
82
+ string :transactional_id, default: nil
30
83
  integer :transactional_timeout, default: 60
31
84
 
32
85
  # Compression
33
- integer :compression_threshold, default: 1
34
- string :compression_codec, default: nil
86
+ integer :compression_threshold, default: 1 # deprecated, not an option for RdKafka
87
+ string :compression_codec, default: "none"
35
88
 
36
89
  # SSL authentication
37
90
  string :ssl_ca_cert, default: nil
@@ -42,10 +95,12 @@ module DeliveryBoy
42
95
  boolean :ssl_ca_certs_from_system, default: false
43
96
  boolean :ssl_verify_hostname, default: true
44
97
 
98
+ # Supported: GSSAPI, PLAIN, SCRAM-SHA-256, SCRAM-SHA-512, OAUTHBEARER
99
+ string :sasl_mechanism, default: nil
45
100
  # SASL authentication
46
101
  string :sasl_gssapi_principal
47
102
  string :sasl_gssapi_keytab
48
- string :sasl_plain_authzid, default: ''
103
+ string :sasl_plain_authzid, default: ""
49
104
  string :sasl_plain_username
50
105
  string :sasl_plain_password
51
106
  string :sasl_scram_username
@@ -53,9 +108,21 @@ module DeliveryBoy
53
108
  string :sasl_scram_mechanism
54
109
  boolean :sasl_over_ssl, default: true
55
110
 
56
- # SASL OAUTHBEARER
111
+ # New consolidated SASL options (librdkafka-aligned)
112
+ string :sasl_username, default: nil
113
+ string :sasl_password, default: nil
114
+
115
+ # SASL OAUTHBEARER (legacy - callback-based, not supported with librdkafka)
57
116
  attr_accessor :sasl_oauth_token_provider
58
117
 
118
+ # SASL OAUTHBEARER OIDC (librdkafka native support)
119
+ string :sasl_oauthbearer_method, default: nil # "oidc" for OIDC-based auth
120
+ string :sasl_oauthbearer_client_id, default: nil
121
+ string :sasl_oauthbearer_client_secret, default: nil
122
+ string :sasl_oauthbearer_token_endpoint_url, default: nil
123
+ string :sasl_oauthbearer_scope, default: nil
124
+ string :sasl_oauthbearer_extensions, default: nil
125
+
59
126
  # AWS IAM authentication
60
127
  string :sasl_aws_msk_iam_access_key_id
61
128
  string :sasl_aws_msk_iam_secret_key_id
@@ -1,4 +1,3 @@
1
1
  module DeliveryBoy
2
2
  ConfigError = Class.new(StandardError)
3
3
  end
4
-