waterdrop 1.2.0.beta1 → 1.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25c083d88a1163c685e9939307feba4294fd3a526f4523692958cdc5d0d04363
4
- data.tar.gz: 300d3e1cce18970d0c9beb105ab6e3b6b7d5eedfc388e3fad7f1cd0db1c204e3
3
+ metadata.gz: 29f20d39798734c2c3530de25b44ff2d8987236adccde1c5fe8b04c624487e4b
4
+ data.tar.gz: 9bd463eac4f7e02a7aad4681e8bcc4e52f809673ea7c6ddbab8c0e0c4d722d52
5
5
  SHA512:
6
- metadata.gz: aa9f0cdfb2285b1f50a71f9a1e84310903e1abc936cd41838f8568a2ddf818b4c83324ccaf7a7c299980a7a8b7d6f0c8fb7fdad65b075e26440bc740be1f20cb
7
- data.tar.gz: fff2c225e42eeb1ab849fb5ea34c900e6bf4b9783541a6087c094647ec8235c6ce6305087119455d2900cfd53c55e7179b27be5b0f29d49ef80f70720f6674ff
6
+ metadata.gz: 883ded4f2e72051543258d96d5c9a9ffd32785a7fb10f9e90c17460fd55616faf812f57711efb75a61355c27296ebf7b25a8c50536df39d7c4b3683cf2f8aac1
7
+ data.tar.gz: 55e13aedda6a2626e6078259a4d3e3da0c99405259bf0c549c66e4bf3e88e6671e7390a8f4e995308b9229138e4c80eace5039d1c4f22f8f0008ff44b55f0485
Binary file
Binary file
@@ -0,0 +1,3 @@
1
+ repository_id: '76b3a28c-d72b-44c7-870b-e5217e2f0d5c'
2
+ api_key: <%= ENV['CODITSU_API_KEY'] %>
3
+ api_secret: <%= ENV['CODITSU_API_SECRET'] %>
@@ -0,0 +1 @@
1
+ open_collective: karafka
data/.gitignore CHANGED
@@ -7,10 +7,11 @@ app.god
7
7
 
8
8
  # minimal Rails specific artifacts
9
9
  db/*.sqlite3
10
- /log/*
10
+ /log/*.log
11
11
  /tmp/*
12
12
  *.gem
13
13
  *.~
14
+ /.coditsu/local.yml
14
15
 
15
16
  # various artifacts
16
17
  **.war
@@ -1 +1 @@
1
- 2.5.0
1
+ 2.6.3
@@ -1,18 +1,37 @@
1
- language: ruby
2
- sudo: false
3
- rvm:
4
- - 2.3.0
5
- - 2.3.1
6
- - 2.3.2
7
- - 2.3.3
8
- - 2.3.4
9
- - 2.4.0
10
- - 2.4.1
11
- - 2.4.2
12
- - 2.5.0
13
- - jruby-head
14
- script: bundle exec rspec spec/
15
- env:
16
- global:
17
- - JRUBY_OPTS='--debug'
18
- install: bundle install --jobs=3 --retry=3
1
+ services:
2
+ - docker
3
+
4
+ dist: trusty
5
+ cache: bundler
6
+
7
+ git:
8
+ depth: false
9
+
10
+ test: &test
11
+ stage: Test
12
+ language: ruby
13
+ before_install:
14
+ - gem install bundler
15
+ - gem update --system
16
+ script: bundle exec rspec
17
+
18
+ jobs:
19
+ include:
20
+ - <<: *test
21
+ rvm: 2.6.3
22
+ - <<: *test
23
+ rvm: 2.5.5
24
+ - <<: *test
25
+ rvm: 2.4.6
26
+
27
+ - stage: coditsu
28
+ language: ruby
29
+ rvm: 2.6.3
30
+ before_install:
31
+ - gem update --system
32
+ - gem install bundler
33
+ script: \curl -sSL https://api.coditsu.io/run/ci | bash
34
+
35
+ stages:
36
+ - coditsu
37
+ - test
@@ -1,6 +1,42 @@
1
1
  # WaterDrop changelog
2
2
 
3
- ## 1.2.0.beta1
3
+ ## 1.3.0.rc1 (2019-07-31)
4
+ - Drop Ruby 2.3 support
5
+ - Drop support for Kafka 0.10 in favor of native support for Kafka 0.11.
6
+ - Ruby 2.6.3 support
7
+ - Support message headers
8
+ - `sasl_over_ssl` support
9
+ - Unlock Ruby Kafka + provide support for 0.7 only
10
+ - #60 - Rename listener to StdoutListener
11
+ - Drop support for Kafka 0.10 in favor of native support for Kafka 0.11.
12
+ - Support ruby-kafka 0.7
13
+ - Support message headers
14
+ - `sasl_over_ssl` support
15
+ - `ssl_client_cert_key_password` support
16
+ - #87 - Make stdout listener as instance
17
+ - Use Zeitwerk for gem code loading
18
+ - #93 - zstd compression support
19
+ - #99 - schemas are renamed to contracts
20
+ - Bump delivery_boy (0.2.7 => 0.2.8)
21
+
22
+ ## 1.2.5
23
+ - Bump deps to match Karafka
24
+ - drop jruby support
25
+ - drop ruby 2.2 support
26
+
27
+ ## 1.2.4
28
+ - Due to multiple requests, unlock of 0.7 with an additional post-install message
29
+
30
+ ## 1.2.3
31
+ - Lock ruby-kafka to 0.6 (0.7 support targeted for WaterDrop 1.3)
32
+
33
+ ## 1.2.2
34
+ - #55 - Codec settings unification and config applier
35
+
36
+ ## 1.2.1
37
+ - #54 - compression_codec api sync with king-konf requirements
38
+
39
+ ## 1.2.0
4
40
  - #45 - Allow specifying a create time for messages
5
41
  - #47 - Support SCRAM once released
6
42
  - #49 - Add lz4 support once merged and released
data/Gemfile CHANGED
@@ -4,7 +4,9 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
- group :development, :test do
7
+ gem 'dry-validation'
8
+
9
+ group :test do
8
10
  gem 'rspec'
9
11
  gem 'simplecov'
10
12
  end
@@ -1,91 +1,102 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- waterdrop (1.2.0.beta1)
5
- delivery_boy (>= 0.2.3)
6
- dry-configurable (~> 0.7)
7
- dry-monitor (~> 0.1)
8
- dry-validation (~> 0.11)
9
- null-logger
10
- ruby-kafka (>= 0.5.3)
4
+ waterdrop (1.3.0.rc1)
5
+ delivery_boy (~> 0.2)
6
+ dry-configurable (~> 0.8)
7
+ dry-monitor (~> 0.3)
8
+ dry-validation (~> 1.2)
9
+ ruby-kafka (>= 0.7.8)
10
+ zeitwerk (~> 2.1)
11
11
 
12
12
  GEM
13
13
  remote: https://rubygems.org/
14
14
  specs:
15
- concurrent-ruby (1.0.5)
16
- delivery_boy (0.2.4)
17
- king_konf (~> 0.1.8)
18
- ruby-kafka (~> 0.5.1)
15
+ concurrent-ruby (1.1.5)
16
+ delivery_boy (0.2.8)
17
+ king_konf (~> 0.3)
18
+ ruby-kafka (~> 0.7.8)
19
19
  diff-lcs (1.3)
20
- docile (1.1.5)
21
- dry-configurable (0.7.0)
20
+ digest-crc (0.4.1)
21
+ docile (1.3.2)
22
+ dry-configurable (0.8.3)
22
23
  concurrent-ruby (~> 1.0)
23
- dry-container (0.6.0)
24
+ dry-core (~> 0.4, >= 0.4.7)
25
+ dry-container (0.7.2)
24
26
  concurrent-ruby (~> 1.0)
25
27
  dry-configurable (~> 0.1, >= 0.1.3)
26
- dry-core (0.4.4)
28
+ dry-core (0.4.8)
27
29
  concurrent-ruby (~> 1.0)
28
- dry-equalizer (0.2.0)
29
- dry-events (0.1.0)
30
+ dry-equalizer (0.2.2)
31
+ dry-events (0.2.0)
30
32
  concurrent-ruby (~> 1.0)
31
33
  dry-core (~> 0.4)
32
34
  dry-equalizer (~> 0.2)
33
- dry-logic (0.4.2)
34
- dry-container (~> 0.2, >= 0.2.6)
35
+ dry-inflector (0.1.2)
36
+ dry-initializer (3.0.1)
37
+ dry-logic (1.0.2)
38
+ concurrent-ruby (~> 1.0)
35
39
  dry-core (~> 0.2)
36
40
  dry-equalizer (~> 0.2)
37
- dry-monitor (0.1.2)
41
+ dry-monitor (0.3.1)
38
42
  dry-configurable (~> 0.5)
43
+ dry-core (~> 0.4)
39
44
  dry-equalizer (~> 0.2)
40
45
  dry-events (~> 0.1)
41
- rouge (~> 2.0, >= 2.2.1)
42
- dry-types (0.12.2)
46
+ dry-schema (1.3.1)
43
47
  concurrent-ruby (~> 1.0)
44
- dry-configurable (~> 0.1)
45
- dry-container (~> 0.3)
46
- dry-core (~> 0.2, >= 0.2.1)
48
+ dry-configurable (~> 0.8, >= 0.8.3)
49
+ dry-core (~> 0.4)
47
50
  dry-equalizer (~> 0.2)
48
- dry-logic (~> 0.4, >= 0.4.2)
49
- inflecto (~> 0.0.0, >= 0.0.2)
50
- dry-validation (0.11.1)
51
+ dry-initializer (~> 3.0)
52
+ dry-logic (~> 1.0)
53
+ dry-types (~> 1.0)
54
+ dry-types (1.1.1)
51
55
  concurrent-ruby (~> 1.0)
52
- dry-configurable (~> 0.1, >= 0.1.3)
53
- dry-core (~> 0.2, >= 0.2.1)
56
+ dry-container (~> 0.3)
57
+ dry-core (~> 0.4, >= 0.4.4)
58
+ dry-equalizer (~> 0.2, >= 0.2.2)
59
+ dry-inflector (~> 0.1, >= 0.1.2)
60
+ dry-logic (~> 1.0, >= 1.0.2)
61
+ dry-validation (1.2.1)
62
+ concurrent-ruby (~> 1.0)
63
+ dry-container (~> 0.7, >= 0.7.1)
64
+ dry-core (~> 0.4)
54
65
  dry-equalizer (~> 0.2)
55
- dry-logic (~> 0.4, >= 0.4.0)
56
- dry-types (~> 0.12.0)
57
- inflecto (0.0.2)
58
- json (2.1.0)
59
- king_konf (0.1.10)
60
- null-logger (0.1.4)
61
- rouge (2.2.1)
62
- rspec (3.7.0)
63
- rspec-core (~> 3.7.0)
64
- rspec-expectations (~> 3.7.0)
65
- rspec-mocks (~> 3.7.0)
66
- rspec-core (3.7.1)
67
- rspec-support (~> 3.7.0)
68
- rspec-expectations (3.7.0)
66
+ dry-initializer (~> 3.0)
67
+ dry-schema (~> 1.0, >= 1.3.1)
68
+ json (2.2.0)
69
+ king_konf (0.3.7)
70
+ rspec (3.8.0)
71
+ rspec-core (~> 3.8.0)
72
+ rspec-expectations (~> 3.8.0)
73
+ rspec-mocks (~> 3.8.0)
74
+ rspec-core (3.8.2)
75
+ rspec-support (~> 3.8.0)
76
+ rspec-expectations (3.8.4)
69
77
  diff-lcs (>= 1.2.0, < 2.0)
70
- rspec-support (~> 3.7.0)
71
- rspec-mocks (3.7.0)
78
+ rspec-support (~> 3.8.0)
79
+ rspec-mocks (3.8.1)
72
80
  diff-lcs (>= 1.2.0, < 2.0)
73
- rspec-support (~> 3.7.0)
74
- rspec-support (3.7.1)
75
- ruby-kafka (0.5.3)
76
- simplecov (0.15.1)
77
- docile (~> 1.1.0)
81
+ rspec-support (~> 3.8.0)
82
+ rspec-support (3.8.2)
83
+ ruby-kafka (0.7.9)
84
+ digest-crc
85
+ simplecov (0.17.0)
86
+ docile (~> 1.1)
78
87
  json (>= 1.8, < 3)
79
88
  simplecov-html (~> 0.10.0)
80
89
  simplecov-html (0.10.2)
90
+ zeitwerk (2.1.9)
81
91
 
82
92
  PLATFORMS
83
93
  ruby
84
94
 
85
95
  DEPENDENCIES
96
+ dry-validation
86
97
  rspec
87
98
  simplecov
88
99
  waterdrop!
89
100
 
90
101
  BUNDLED WITH
91
- 1.16.1
102
+ 2.0.2
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # WaterDrop
2
2
 
3
- [![Build Status](https://travis-ci.org/karafka/waterdrop.png)](https://travis-ci.org/karafka/waterdrop)
3
+ [![Build Status](https://travis-ci.org/karafka/waterdrop.svg)](https://travis-ci.org/karafka/waterdrop)
4
4
  [![Join the chat at https://gitter.im/karafka/karafka](https://badges.gitter.im/karafka/karafka.svg)](https://gitter.im/karafka/karafka?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
5
 
6
6
  Gem used to send messages to Kafka in an easy way with an extra validation layer. It is a part of the [Karafka](https://github.com/karafka/karafka) ecosystem.
@@ -11,7 +11,7 @@ It is:
11
11
 
12
12
  - Thread safe
13
13
  - Supports sync and async producers
14
- - Working with 0.10.1+ Kafka
14
+ - Working with 0.11+ Kafka
15
15
 
16
16
  ## Installation
17
17
 
@@ -100,10 +100,11 @@ Both ```SyncProducer``` and ```AsyncProducer``` accept following options:
100
100
  | Option | Required | Value type | Description |
101
101
  |-------------------- |----------|------------|---------------------------------------------------------------------|
102
102
  | ```topic``` | true | String | The Kafka topic that should be written to |
103
- | ```key``` | false | String | The key that should be set on the Kafka message |
103
+ | ```key``` | false | String | The key that should be set in the Kafka message |
104
104
  | ```partition``` | false | Integer | A specific partition number that should be written to |
105
105
  | ```partition_key``` | false | String | A string that can be used to deterministically select the partition |
106
106
  | ```create_time``` | false | Time | The timestamp that should be set on the message |
107
+ | ```headers``` | false | Hash | Headers for the message |
107
108
 
108
109
  Keep in mind, that message you want to send should be either binary or stringified (to_s, to_json, etc).
109
110
 
@@ -117,7 +118,7 @@ Keep in mind, that message you want to send should be either binary or stringifi
117
118
 
118
119
  First, thank you for considering contributing to WaterDrop! It's people like you that make the open source community such a great community!
119
120
 
120
- Each pull request must pass all the rspec specs and meet our quality requirements.
121
+ Each pull request must pass all the RSpec specs and meet our quality requirements.
121
122
 
122
123
  To check if everything is as it should be, we use [Coditsu](https://coditsu.io) that combines multiple linters and code analyzers for both code and documentation. Once you're done with your changes, submit a pull request.
123
124
 
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhtYWNp
3
+ ZWovREM9bWVuc2ZlbGQvREM9cGwwHhcNMTkwNzMwMTQ1NDU0WhcNMjAwNzI5MTQ1
4
+ NDU0WjAjMSEwHwYDVQQDDBhtYWNpZWovREM9bWVuc2ZlbGQvREM9cGwwggGiMA0G
5
+ CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC9fCwtaHZG2SyyNXiH8r0QbJQx/xxl
6
+ dkvwWz9QGJO+O8rEx20FB1Ab+MVkfOscwIv5jWpmk1U9whzDPl1uFtIbgu+sk+Zb
7
+ uQlZyK/DPN6c+/BbBL+RryTBRyvkPLoCVwm7uxc/JZ1n4AI6eF4cCZ2ieZ9QgQbU
8
+ MQs2QPqs9hT50Ez/40GnOdadVfiDDGz+NME2C4ms0BriXwZ1tcRTfJIHe2xjIbbb
9
+ y5qRGfsLKcgMzvLQR24olixyX1MR0s4+Wveq3QL/gBhL4veUcv+UABJA8IJR0kyB
10
+ seHHutusiwZ1v3SjjjW1xLLrc2ARV0mgCb0WaK2T4iA3oFTGLh6Ydz8LNl31KQFv
11
+ 94nRd8IhmJxrhQ6dQ/WT9IXoa5S9lfT5lPJeINemH4/6QPABzf9W2IZlCdI9wCdB
12
+ TBaw57MKneGAYZiKjw6OALSy2ltQUCl3RqFl3VP7n8uFy1U987Q5VIIQ3O1UUsQD
13
+ Oe/h+r7GUU4RSPKgPlrwvW9bD/UQ+zF51v8CAwEAAaN3MHUwCQYDVR0TBAIwADAL
14
+ BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFJNIBHdfEUD7TqHqIer2YhWaWhwcMB0GA1Ud
15
+ EQQWMBSBEm1hY2llakBtZW5zZmVsZC5wbDAdBgNVHRIEFjAUgRJtYWNpZWpAbWVu
16
+ c2ZlbGQucGwwDQYJKoZIhvcNAQELBQADggGBAKA4eqko6BTNhlysip6rfBkVTGri
17
+ ZXsL+kRb2hLvsQJS/kLyM21oMlu+LN0aPj3qEFR8mE/YeDD8rLAfruBRTltPNbR7
18
+ xA5eE1gkxY5LfExUtK3b2wPqfmo7mZgfcsMwfYg/tUXw1WpBCnrhAJodpGH6SXmp
19
+ A40qFUZst0vjiOoO+aTblIHPmMJXoZ3K42dTlNKlEiDKUWMRKSgpjjYGEYalFNWI
20
+ hHfCz2r8L2t+dYdMZg1JGbEkq4ADGsAA8ioZIpJd7V4hI17u5TCdi7X5wh/0gN0E
21
+ CgP+nLox3D+l2q0QuQEkayr+auFYkzTCkF+BmEk1D0Ru4mcf3F4CJvEmW4Pzbjqt
22
+ i1tsCWPtJ4E/UUKnKaWKqGbjrjHJ0MuShYzHkodox5IOiCXIQg+1+YSzfXUV6WEK
23
+ KJG/fhg1JV5vVDdVy6x+tv5SQ5ctU0feCsVfESi3rE3zRd+nvzE9HcZ5aXeL1UtJ
24
+ nT5Xrioegu2w1jPyVEgyZgTZC5rvD0nNS5sFNQ==
25
+ -----END CERTIFICATE-----
@@ -1,6 +1,19 @@
1
1
  en:
2
- errors:
3
- broker_schema?: >
4
- has an invalid format.
5
- Expected schema, host and port number.
6
- Example: kafka://127.0.0.1:9092 or kafka+ssl://127.0.0.1:9092
2
+ dry_validation:
3
+ errors:
4
+ broker_schema: >
5
+ has an invalid format.
6
+ Expected schema, host and port number.
7
+ Example: kafka://127.0.0.1:9092 or kafka+ssl://127.0.0.1:9092
8
+ ssl_client_cert_with_ssl_client_cert_key: >
9
+ Both ssl_client_cert and ssl_client_cert_key need to be provided.
10
+ ssl_client_cert_key_with_ssl_client_cert: >
11
+ Both ssl_client_cert_key and ssl_client_cert need to be provided.
12
+ ssl_client_cert_chain_with_ssl_client_cert: >
13
+ Both ssl_client_cert_chain and ssl_client_cert need to be provided.
14
+ ssl_client_cert_chain_with_ssl_client_cert_key: >
15
+ Both ssl_client_cert_chain and ssl_client_cert_key need to be provided.
16
+ ssl_client_cert_key_password_with_ssl_client_cert_key: >
17
+ Both ssl_client_cert_key_password and ssl_client_cert_key need to be provided.
18
+ sasl_oauth_token_provider_respond_to_token: >
19
+ sasl_oauth_token_provider needs to respond to a #token method.
@@ -4,16 +4,13 @@
4
4
  %w[
5
5
  json
6
6
  delivery_boy
7
- null_logger
8
7
  singleton
9
8
  dry-configurable
10
9
  dry/monitor/notifications
11
10
  dry-validation
11
+ zeitwerk
12
12
  ].each { |lib| require lib }
13
13
 
14
- # Internal components
15
- base_path = File.dirname(__FILE__) + '/water_drop'
16
-
17
14
  # WaterDrop library
18
15
  module WaterDrop
19
16
  class << self
@@ -23,22 +20,8 @@ module WaterDrop
23
20
  # @param [Block] block configuration block
24
21
  def setup(&block)
25
22
  Config.setup(&block)
26
-
27
23
  DeliveryBoy.logger = self.logger = config.logger
28
-
29
- # Recursive lambda for mapping config down to delivery boy
30
- applier = lambda { |db_config, h|
31
- h.each do |k, v|
32
- applier.call(db_config, v) && next if v.is_a?(Hash)
33
- next unless db_config.respond_to?(:"#{k}=")
34
- db_config.public_send(:"#{k}=", v)
35
- end
36
- }
37
-
38
- DeliveryBoy.config.tap do |config|
39
- config.brokers = Config.config.kafka.seed_brokers
40
- applier.call(config, Config.config.to_h)
41
- end
24
+ ConfigApplier.call(DeliveryBoy.config, Config.config.to_h)
42
25
  end
43
26
 
44
27
  # @return [WaterDrop::Config] config instance
@@ -53,20 +36,13 @@ module WaterDrop
53
36
 
54
37
  # @return [String] root path of this gem
55
38
  def gem_root
56
- Pathname.new(File.expand_path('../..', __FILE__))
39
+ Pathname.new(File.expand_path('..', __dir__))
57
40
  end
58
41
  end
59
42
  end
60
43
 
61
- %w[
62
- version
63
- instrumentation/monitor
64
- instrumentation/listener
65
- schemas/message_options
66
- schemas/config
67
- config
68
- errors
69
- base_producer
70
- sync_producer
71
- async_producer
72
- ].each { |lib| require "#{base_path}/#{lib}" }
44
+ Zeitwerk::Loader
45
+ .for_gem
46
+ .tap { |loader| loader.ignore("#{__dir__}/waterdrop.rb") }
47
+ .tap(&:setup)
48
+ .tap(&:eager_load)
@@ -19,8 +19,8 @@ module WaterDrop
19
19
  d_method = WaterDrop.config.raise_on_buffer_overflow ? :deliver_async! : :deliver_async
20
20
 
21
21
  DeliveryBoy.send(d_method, message, options)
22
- rescue Kafka::Error => error
23
- graceful_attempt?(attempts_count, message, options, error) ? retry : raise(error)
22
+ rescue Kafka::Error => e
23
+ graceful_attempt?(attempts_count, message, options, e) ? retry : raise(e)
24
24
  end
25
25
  end
26
26
  end
@@ -4,6 +4,12 @@ module WaterDrop
4
4
  # Base messages producer that contains all the logic that is exactly the same for both
5
5
  # sync and async producers
6
6
  class BaseProducer
7
+ # Contract for checking the correctness of the provided data that someone wants to
8
+ # dispatch to Kafka
9
+ SCHEMA = Contracts::MessageOptions.new.freeze
10
+
11
+ private_constant :SCHEMA
12
+
7
13
  class << self
8
14
  private
9
15
 
@@ -12,18 +18,19 @@ module WaterDrop
12
18
  # @raise [WaterDrop::Errors::InvalidMessageOptions] raised when message options are
13
19
  # somehow invalid and we cannot perform delivery because of that
14
20
  def validate!(options)
15
- validation_result = Schemas::MessageOptions.call(options)
21
+ validation_result = SCHEMA.call(options)
16
22
  return true if validation_result.success?
23
+
17
24
  raise Errors::InvalidMessageOptions, validation_result.errors
18
25
  end
19
26
 
20
27
  # Upon failed delivery, we may try to resend a message depending on the attempt number
21
- # or reraise an error if we're unable to do that after given number of retries
28
+ # or re-raise an error if we're unable to do that after given number of retries
22
29
  # This method checks that and also instruments errors and retries for the delivery
23
30
  # @param attempts_count [Integer] number of attempt (starting from 1) for the delivery
24
31
  # @param message [String] message that we want to send to Kafka
25
32
  # @param options [Hash] options (including topic) for producer
26
- # @param error [Kafka::Error] error that occured
33
+ # @param error [Kafka::Error] error that occurred
27
34
  # @return [Boolean] true if this is a graceful attempt and we can retry or false it this
28
35
  # was the final one and we should deal with the fact, that we cannot deliver a given
29
36
  # message
@@ -3,18 +3,24 @@
3
3
  # Configuration and descriptions are based on the delivery boy zendesk gem
4
4
  # @see https://github.com/zendesk/delivery_boy
5
5
  module WaterDrop
6
- # Configurator for setting up all options required by WaterDrop
6
+ # Configuration object for setting up all options required by WaterDrop
7
7
  class Config
8
8
  extend Dry::Configurable
9
9
 
10
+ # Config schema definition
11
+ # @note We use a single instance not to create new one upon each usage
12
+ SCHEMA = Contracts::Config.new.freeze
13
+
14
+ private_constant :SCHEMA
15
+
10
16
  # WaterDrop options
11
17
  # option client_id [String] identifier of this producer
12
18
  setting :client_id, 'waterdrop'
13
19
  # option [Instance, nil] logger that we want to use or nil to fallback to ruby-kafka logger
14
- setting :logger, NullLogger.new
20
+ setting :logger, Logger.new($stdout, level: Logger::WARN)
15
21
  # option [Instance] monitor that we want to use. See instrumentation part of the README for
16
22
  # more details
17
- setting :monitor, WaterDrop::Instrumentation::Monitor.instance
23
+ setting :monitor, WaterDrop::Instrumentation::Monitor.new
18
24
  # option [Boolean] should we send messages. Setting this to false can be really useful when
19
25
  # testing and or developing because when set to false, won't actually ping Kafka
20
26
  setting :deliver, true
@@ -108,21 +114,20 @@ module WaterDrop
108
114
  setting :sasl_scram_password, nil
109
115
  # option sasl_scram_mechanism [String, nil] Scram mechanism, either 'sha256' or 'sha512'
110
116
  setting :sasl_scram_mechanism, nil
111
- end
112
-
113
- # option producer [Hash] - optional - producer configuration options
114
- setting :producer do
115
- # option compression_codec [Symbol] Sets producer compression codec
116
- # More: https://github.com/zendesk/ruby-kafka#compression
117
- # More: https://github.com/zendesk/ruby-kafka/blob/master/lib/kafka/compression.rb
118
- setting :compression_codec, nil
119
- # option compression_codec [Integer] Sets producer compression threshold
120
- # More: https://github.com/zendesk/ruby-kafka#compression
121
- setting :compression_threshold, 1
117
+ # option sasl_over_ssl [Boolean] whether to enforce SSL with SASL
118
+ setting :sasl_over_ssl, true
119
+ # option ssl_client_cert_chain [String, nil] client cert chain or nil if not used
120
+ setting :ssl_client_cert_chain, nil
121
+ # option ssl_client_cert_key_password [String, nil] the password required to read
122
+ # the ssl_client_cert_key
123
+ setting :ssl_client_cert_key_password, nil
124
+ # @param sasl_oauth_token_provider [Object, nil] OAuthBearer Token Provider instance that
125
+ # implements method token.
126
+ setting :sasl_oauth_token_provider, nil
122
127
  end
123
128
 
124
129
  class << self
125
- # Configurating method
130
+ # Configuration method
126
131
  # @yield Runs a block of code providing a config singleton instance to it
127
132
  # @yieldparam [WaterDrop::Config] WaterDrop config instance
128
133
  def setup
@@ -139,9 +144,10 @@ module WaterDrop
139
144
  # @raise [WaterDrop::Errors::InvalidConfiguration] raised when something is wrong with
140
145
  # the configuration
141
146
  def validate!(config_hash)
142
- validation_result = Schemas::Config.call(config_hash)
147
+ validation_result = SCHEMA.call(config_hash)
143
148
  return true if validation_result.success?
144
- raise Errors::InvalidConfiguration, validation_result.errors
149
+
150
+ raise Errors::InvalidConfiguration, validation_result.errors.to_h
145
151
  end
146
152
  end
147
153
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WaterDrop
4
+ # Engine used to propagate config application to DeliveryBoy with corner case handling
5
+ module ConfigApplier
6
+ class << self
7
+ # @param delivery_boy_config [DeliveryBoy::Config] delivery boy config instance
8
+ # @param settings [Hash] hash with WaterDrop settings
9
+ def call(delivery_boy_config, settings)
10
+ # Recursive lambda for mapping config down to delivery boy
11
+ settings.each do |key, value|
12
+ call(delivery_boy_config, value) && next if value.is_a?(Hash)
13
+
14
+ # If this is a special case that needs manual setup instead of a direct reassignment
15
+ if respond_to?(key, true)
16
+ send(key, delivery_boy_config, value)
17
+ else
18
+ # If this setting is our internal one, we should not sync it with the delivery boy
19
+ next unless delivery_boy_config.respond_to?(:"#{key}=")
20
+
21
+ delivery_boy_config.public_send(:"#{key}=", value)
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ # Extra setup for the compression codec as it behaves differently than other settings
29
+ # that are ported 1:1 from ruby-kafka
30
+ # For some crazy reason, delivery boy requires compression codec as a string, when
31
+ # ruby-kafka as a symbol. We follow ruby-kafka internal design, so we had to mimic
32
+ # that by assigning a string version that down the road will be symbolized again
33
+ # by delivery boy
34
+ # @param delivery_boy_config [DeliveryBoy::Config] delivery boy config instance
35
+ # @param codec_name [Symbol] codec name as a symbol
36
+ def compression_codec(delivery_boy_config, codec_name)
37
+ # If there is no compression codec, we don't apply anything
38
+ return unless codec_name
39
+
40
+ delivery_boy_config.compression_codec = codec_name.to_s
41
+ end
42
+
43
+ # We use the "seed_brokers" name and DeliveryBoy uses "brokers" so we pass the values
44
+ # manually
45
+ # @param delivery_boy_config [DeliveryBoy::Config] delivery boy config instance
46
+ # @param seed_brokers [Array<String>] kafka seed brokers
47
+ def seed_brokers(delivery_boy_config, seed_brokers)
48
+ delivery_boy_config.brokers = seed_brokers
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WaterDrop
4
+ # Namespace for all the contracts for config validations
5
+ module Contracts
6
+ # Regex to check that topic has a valid format
7
+ TOPIC_REGEXP = /\A(\w|\-|\.)+\z/.freeze
8
+ end
9
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WaterDrop
4
+ module Contracts
5
+ # Contract with validation rules for WaterDrop configuration details
6
+ class Config < Dry::Validation::Contract
7
+ # Valid uri schemas of Kafka broker url
8
+ URI_SCHEMES = %w[kafka kafka+ssl plaintext ssl].freeze
9
+
10
+ # Available sasl scram mechanism of authentication (plus nil)
11
+ SASL_SCRAM_MECHANISMS = %w[sha256 sha512].freeze
12
+
13
+ # Supported compression codecs
14
+ COMPRESSION_CODECS = %i[snappy gzip lz4 zstd].freeze
15
+
16
+ config.messages.load_paths << File.join(WaterDrop.gem_root, 'config', 'errors.yml')
17
+
18
+ class << self
19
+ private
20
+
21
+ # Builder for kafka scoped data custom rules
22
+ # @param keys [Symbol, Hash] the keys names
23
+ # @param block [Proc] block we want to run with validations within the kafka scope
24
+ def kafka_scope_rule(*keys, &block)
25
+ rule(*[:kafka].product(keys)) do
26
+ instance_exec(values[:kafka], &block)
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # Uri validator to check if uri is in a Kafka acceptable format
34
+ # @param uri [String] uri we want to validate
35
+ # @return [Boolean] true if it is a valid uri, otherwise false
36
+ def broker_schema?(uri)
37
+ uri = URI.parse(uri)
38
+ URI_SCHEMES.include?(uri.scheme) && uri.port
39
+ rescue URI::InvalidURIError
40
+ false
41
+ end
42
+
43
+ params do
44
+ required(:client_id).filled(:str?, format?: Contracts::TOPIC_REGEXP)
45
+ required(:logger).filled
46
+ required(:deliver).filled(:bool?)
47
+ required(:raise_on_buffer_overflow).filled(:bool?)
48
+
49
+ required(:kafka).schema do
50
+ required(:seed_brokers).value(:array, :filled?).each(:str?)
51
+ required(:connect_timeout).filled(:int?, gt?: 0)
52
+ required(:socket_timeout).filled(:int?, gt?: 0)
53
+ required(:compression_threshold).filled(:int?, gteq?: 1)
54
+ optional(:compression_codec).maybe(included_in?: COMPRESSION_CODECS)
55
+
56
+ required(:max_buffer_bytesize).filled(:int?, gt?: 0)
57
+ required(:max_buffer_size).filled(:int?, gt?: 0)
58
+ required(:max_queue_size).filled(:int?, gt?: 0)
59
+
60
+ required(:ack_timeout).filled(:int?, gt?: 0)
61
+ required(:delivery_interval).filled(:int?, gteq?: 0)
62
+ required(:delivery_threshold).filled(:int?, gteq?: 0)
63
+
64
+ required(:max_retries).filled(:int?, gteq?: 0)
65
+ required(:retry_backoff).filled(:int?, gteq?: 0)
66
+ required(:required_acks).filled(included_in?: [1, 0, -1, :all])
67
+
68
+ %i[
69
+ ssl_ca_cert
70
+ ssl_ca_cert_file_path
71
+ ssl_client_cert
72
+ ssl_client_cert_key
73
+ ssl_client_cert_chain
74
+ ssl_client_cert_key_password
75
+ sasl_gssapi_principal
76
+ sasl_gssapi_keytab
77
+ sasl_plain_authzid
78
+ sasl_plain_username
79
+ sasl_plain_password
80
+ sasl_scram_username
81
+ sasl_scram_password
82
+ ].each do |encryption_attribute|
83
+ optional(encryption_attribute).maybe(:str?)
84
+ end
85
+
86
+ optional(:ssl_ca_certs_from_system).maybe(:bool?)
87
+ optional(:sasl_over_ssl).maybe(:bool?)
88
+ optional(:sasl_oauth_token_provider).value(:any)
89
+
90
+ # It's not with other encryptions as it has some more rules
91
+ optional(:sasl_scram_mechanism)
92
+ .maybe(:str?, included_in?: SASL_SCRAM_MECHANISMS)
93
+ end
94
+ end
95
+
96
+ kafka_scope_rule(:seed_brokers) do |kafka|
97
+ unless kafka[:seed_brokers].all?(&method(:broker_schema?))
98
+ key(%i[kafka seed_brokers]).failure(:broker_schema)
99
+ end
100
+ end
101
+
102
+ kafka_scope_rule(:ssl_client_cert, :ssl_client_cert_key) do |kafka|
103
+ if kafka[:ssl_client_cert] &&
104
+ kafka[:ssl_client_cert_key].nil?
105
+ key(%i[kafka ssl_client_cert_key]).failure(:ssl_client_cert_with_ssl_client_cert_key)
106
+ end
107
+ end
108
+
109
+ kafka_scope_rule(:ssl_client_cert_key, :ssl_client_cert) do |kafka|
110
+ if kafka[:ssl_client_cert_key] &&
111
+ kafka[:ssl_client_cert].nil?
112
+ key.failure(:ssl_client_cert_key_with_ssl_client_cert)
113
+ end
114
+ end
115
+
116
+ kafka_scope_rule(:ssl_client_cert_chain, :ssl_client_cert) do |kafka|
117
+ if kafka[:ssl_client_cert_chain] &&
118
+ kafka[:ssl_client_cert].nil?
119
+ key.failure(:ssl_client_cert_chain_with_ssl_client_cert)
120
+ end
121
+ end
122
+
123
+ kafka_scope_rule(:ssl_client_cert_key_password, :ssl_client_cert_key) do |kafka|
124
+ if kafka[:ssl_client_cert_key_password] &&
125
+ kafka[:ssl_client_cert_key].nil?
126
+ key.failure(:ssl_client_cert_key_password_with_ssl_client_cert_key)
127
+ end
128
+ end
129
+
130
+ kafka_scope_rule(:sasl_oauth_token_provider) do |kafka|
131
+ if kafka[:sasl_oauth_token_provider] &&
132
+ !kafka[:sasl_oauth_token_provider].respond_to?(:token)
133
+ key.failure(:sasl_oauth_token_provider_respond_to_token)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WaterDrop
4
+ module Contracts
5
+ # Contract with validation rules for validating that all the message options that
6
+ # we provide to producer ale valid and usable
7
+ # @note Does not validate message itself as it is not our concern
8
+ class MessageOptions < Dry::Validation::Contract
9
+ params do
10
+ required(:topic).filled(:str?, format?: TOPIC_REGEXP)
11
+ optional(:key).maybe(:str?, :filled?)
12
+ optional(:partition).filled(:int?, gteq?: 0)
13
+ optional(:partition_key).maybe(:str?, :filled?)
14
+ optional(:create_time).maybe(:time?)
15
+ optional(:headers).maybe(:hash?)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -6,10 +6,10 @@ module WaterDrop
6
6
  # Base class for all the WaterDrop internal errors
7
7
  BaseError = Class.new(StandardError)
8
8
 
9
- # Raised when configuration doesn't match with validation schema
9
+ # Raised when configuration doesn't match with validation contract
10
10
  InvalidConfiguration = Class.new(BaseError)
11
11
 
12
- # Raised when we try to send message with invalid optionss
12
+ # Raised when we try to send message with invalid options
13
13
  InvalidMessageOptions = Class.new(BaseError)
14
14
 
15
15
  # Raised when want to hook up to an event that is not registered and supported
@@ -5,13 +5,11 @@ module WaterDrop
5
5
  module Instrumentation
6
6
  # Monitor is used to hookup external monitoring services to monitor how WaterDrop works
7
7
  # Since it is a pub-sub based on dry-monitor, you can use as many subscribers/loggers at the
8
- # same time, which means that you might have for example file logging and newrelic at the same
8
+ # same time, which means that you might have for example file logging and NewRelic at the same
9
9
  # time
10
10
  # @note This class acts as a singleton because we are only permitted to have single monitor
11
11
  # per running process (just as logger)
12
12
  class Monitor < Dry::Monitor::Notifications
13
- include Singleton
14
-
15
13
  # List of events that we support in the system and to which a monitor client can hook up
16
14
  # @note The non-error once support timestamp benchmarking
17
15
  BASE_EVENTS = %w[
@@ -35,6 +33,7 @@ module WaterDrop
35
33
  def subscribe(event_name_or_listener)
36
34
  return super unless event_name_or_listener.is_a?(String)
37
35
  return super if available_events.include?(event_name_or_listener)
36
+
38
37
  raise Errors::UnregisteredMonitorEvent, event_name_or_listener
39
38
  end
40
39
 
@@ -6,7 +6,7 @@ module WaterDrop
6
6
  # It can be removed/replaced or anything without any harm to the Waterdrop flow
7
7
  # @note It is a module as we can use it then as a part of the Karafka framework listener
8
8
  # as well as we can use it standalone
9
- module Listener
9
+ class StdoutListener
10
10
  # Log levels that we use in this particular listener
11
11
  USED_LOG_LEVELS = %i[
12
12
  info
@@ -33,20 +33,12 @@ module WaterDrop
33
33
 
34
34
  info "Attempt #{attempts_count} of delivery to: #{options} because of #{error}"
35
35
  end
36
-
37
- module_function error_name
38
- module_function retry_name
39
- public error_name
40
- public retry_name
41
36
  end
42
37
 
43
38
  USED_LOG_LEVELS.each do |log_level|
44
39
  define_method log_level do |*args|
45
40
  WaterDrop.logger.send(log_level, *args)
46
41
  end
47
-
48
- module_function log_level
49
- private_class_method log_level
50
42
  end
51
43
  end
52
44
  end
@@ -17,8 +17,8 @@ module WaterDrop
17
17
  return unless WaterDrop.config.deliver
18
18
 
19
19
  DeliveryBoy.deliver(message, options)
20
- rescue Kafka::Error => error
21
- graceful_attempt?(attempts_count, message, options, error) ? retry : raise(error)
20
+ rescue Kafka::Error => e
21
+ graceful_attempt?(attempts_count, message, options, e) ? retry : raise(e)
22
22
  end
23
23
  end
24
24
  end
@@ -3,5 +3,5 @@
3
3
  # WaterDrop library
4
4
  module WaterDrop
5
5
  # Current WaterDrop version
6
- VERSION = '1.2.0.beta1'
6
+ VERSION = '1.3.0.rc1'
7
7
  end
File without changes
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  require 'water_drop/version'
@@ -16,14 +16,20 @@ Gem::Specification.new do |spec|
16
16
  spec.description = spec.summary
17
17
  spec.license = 'MIT'
18
18
 
19
- spec.add_dependency 'delivery_boy', '>= 0.2.3'
20
- spec.add_dependency 'dry-configurable', '~> 0.7'
21
- spec.add_dependency 'dry-monitor', '~> 0.1'
22
- spec.add_dependency 'dry-validation', '~> 0.11'
23
- spec.add_dependency 'null-logger'
24
- spec.add_dependency 'ruby-kafka', '>= 0.5.3'
19
+ spec.add_dependency 'delivery_boy', '~> 0.2'
20
+ spec.add_dependency 'dry-configurable', '~> 0.8'
21
+ spec.add_dependency 'dry-monitor', '~> 0.3'
22
+ spec.add_dependency 'dry-validation', '~> 1.2'
23
+ spec.add_dependency 'ruby-kafka', '>= 0.7.8'
24
+ spec.add_dependency 'zeitwerk', '~> 2.1'
25
25
 
26
- spec.required_ruby_version = '>= 2.2.0'
26
+ spec.required_ruby_version = '>= 2.4.0'
27
+
28
+ spec.cert_chain = ['certs/mensfeld.pem']
29
+
30
+ if $PROGRAM_NAME.end_with?('gem')
31
+ spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem')
32
+ end
27
33
 
28
34
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
29
35
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,99 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waterdrop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0.beta1
4
+ version: 1.3.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain: []
11
- date: 2018-02-16 00:00:00.000000000 Z
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhtYWNp
14
+ ZWovREM9bWVuc2ZlbGQvREM9cGwwHhcNMTkwNzMwMTQ1NDU0WhcNMjAwNzI5MTQ1
15
+ NDU0WjAjMSEwHwYDVQQDDBhtYWNpZWovREM9bWVuc2ZlbGQvREM9cGwwggGiMA0G
16
+ CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC9fCwtaHZG2SyyNXiH8r0QbJQx/xxl
17
+ dkvwWz9QGJO+O8rEx20FB1Ab+MVkfOscwIv5jWpmk1U9whzDPl1uFtIbgu+sk+Zb
18
+ uQlZyK/DPN6c+/BbBL+RryTBRyvkPLoCVwm7uxc/JZ1n4AI6eF4cCZ2ieZ9QgQbU
19
+ MQs2QPqs9hT50Ez/40GnOdadVfiDDGz+NME2C4ms0BriXwZ1tcRTfJIHe2xjIbbb
20
+ y5qRGfsLKcgMzvLQR24olixyX1MR0s4+Wveq3QL/gBhL4veUcv+UABJA8IJR0kyB
21
+ seHHutusiwZ1v3SjjjW1xLLrc2ARV0mgCb0WaK2T4iA3oFTGLh6Ydz8LNl31KQFv
22
+ 94nRd8IhmJxrhQ6dQ/WT9IXoa5S9lfT5lPJeINemH4/6QPABzf9W2IZlCdI9wCdB
23
+ TBaw57MKneGAYZiKjw6OALSy2ltQUCl3RqFl3VP7n8uFy1U987Q5VIIQ3O1UUsQD
24
+ Oe/h+r7GUU4RSPKgPlrwvW9bD/UQ+zF51v8CAwEAAaN3MHUwCQYDVR0TBAIwADAL
25
+ BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFJNIBHdfEUD7TqHqIer2YhWaWhwcMB0GA1Ud
26
+ EQQWMBSBEm1hY2llakBtZW5zZmVsZC5wbDAdBgNVHRIEFjAUgRJtYWNpZWpAbWVu
27
+ c2ZlbGQucGwwDQYJKoZIhvcNAQELBQADggGBAKA4eqko6BTNhlysip6rfBkVTGri
28
+ ZXsL+kRb2hLvsQJS/kLyM21oMlu+LN0aPj3qEFR8mE/YeDD8rLAfruBRTltPNbR7
29
+ xA5eE1gkxY5LfExUtK3b2wPqfmo7mZgfcsMwfYg/tUXw1WpBCnrhAJodpGH6SXmp
30
+ A40qFUZst0vjiOoO+aTblIHPmMJXoZ3K42dTlNKlEiDKUWMRKSgpjjYGEYalFNWI
31
+ hHfCz2r8L2t+dYdMZg1JGbEkq4ADGsAA8ioZIpJd7V4hI17u5TCdi7X5wh/0gN0E
32
+ CgP+nLox3D+l2q0QuQEkayr+auFYkzTCkF+BmEk1D0Ru4mcf3F4CJvEmW4Pzbjqt
33
+ i1tsCWPtJ4E/UUKnKaWKqGbjrjHJ0MuShYzHkodox5IOiCXIQg+1+YSzfXUV6WEK
34
+ KJG/fhg1JV5vVDdVy6x+tv5SQ5ctU0feCsVfESi3rE3zRd+nvzE9HcZ5aXeL1UtJ
35
+ nT5Xrioegu2w1jPyVEgyZgTZC5rvD0nNS5sFNQ==
36
+ -----END CERTIFICATE-----
37
+ date: 2019-07-31 00:00:00.000000000 Z
12
38
  dependencies:
13
39
  - !ruby/object:Gem::Dependency
14
40
  name: delivery_boy
15
41
  requirement: !ruby/object:Gem::Requirement
16
42
  requirements:
17
- - - ">="
43
+ - - "~>"
18
44
  - !ruby/object:Gem::Version
19
- version: 0.2.3
45
+ version: '0.2'
20
46
  type: :runtime
21
47
  prerelease: false
22
48
  version_requirements: !ruby/object:Gem::Requirement
23
49
  requirements:
24
- - - ">="
50
+ - - "~>"
25
51
  - !ruby/object:Gem::Version
26
- version: 0.2.3
52
+ version: '0.2'
27
53
  - !ruby/object:Gem::Dependency
28
54
  name: dry-configurable
29
55
  requirement: !ruby/object:Gem::Requirement
30
56
  requirements:
31
57
  - - "~>"
32
58
  - !ruby/object:Gem::Version
33
- version: '0.7'
59
+ version: '0.8'
34
60
  type: :runtime
35
61
  prerelease: false
36
62
  version_requirements: !ruby/object:Gem::Requirement
37
63
  requirements:
38
64
  - - "~>"
39
65
  - !ruby/object:Gem::Version
40
- version: '0.7'
66
+ version: '0.8'
41
67
  - !ruby/object:Gem::Dependency
42
68
  name: dry-monitor
43
69
  requirement: !ruby/object:Gem::Requirement
44
70
  requirements:
45
71
  - - "~>"
46
72
  - !ruby/object:Gem::Version
47
- version: '0.1'
73
+ version: '0.3'
48
74
  type: :runtime
49
75
  prerelease: false
50
76
  version_requirements: !ruby/object:Gem::Requirement
51
77
  requirements:
52
78
  - - "~>"
53
79
  - !ruby/object:Gem::Version
54
- version: '0.1'
80
+ version: '0.3'
55
81
  - !ruby/object:Gem::Dependency
56
82
  name: dry-validation
57
83
  requirement: !ruby/object:Gem::Requirement
58
84
  requirements:
59
85
  - - "~>"
60
86
  - !ruby/object:Gem::Version
61
- version: '0.11'
87
+ version: '1.2'
62
88
  type: :runtime
63
89
  prerelease: false
64
90
  version_requirements: !ruby/object:Gem::Requirement
65
91
  requirements:
66
92
  - - "~>"
67
93
  - !ruby/object:Gem::Version
68
- version: '0.11'
94
+ version: '1.2'
69
95
  - !ruby/object:Gem::Dependency
70
- name: null-logger
96
+ name: ruby-kafka
71
97
  requirement: !ruby/object:Gem::Requirement
72
98
  requirements:
73
99
  - - ">="
74
100
  - !ruby/object:Gem::Version
75
- version: '0'
101
+ version: 0.7.8
76
102
  type: :runtime
77
103
  prerelease: false
78
104
  version_requirements: !ruby/object:Gem::Requirement
79
105
  requirements:
80
106
  - - ">="
81
107
  - !ruby/object:Gem::Version
82
- version: '0'
108
+ version: 0.7.8
83
109
  - !ruby/object:Gem::Dependency
84
- name: ruby-kafka
110
+ name: zeitwerk
85
111
  requirement: !ruby/object:Gem::Requirement
86
112
  requirements:
87
- - - ">="
113
+ - - "~>"
88
114
  - !ruby/object:Gem::Version
89
- version: 0.5.3
115
+ version: '2.1'
90
116
  type: :runtime
91
117
  prerelease: false
92
118
  version_requirements: !ruby/object:Gem::Requirement
93
119
  requirements:
94
- - - ">="
120
+ - - "~>"
95
121
  - !ruby/object:Gem::Version
96
- version: 0.5.3
122
+ version: '2.1'
97
123
  description: Kafka messaging made easy!
98
124
  email:
99
125
  - maciej@mensfeld.pl
@@ -101,6 +127,8 @@ executables: []
101
127
  extensions: []
102
128
  extra_rdoc_files: []
103
129
  files:
130
+ - ".coditsu/ci.yml"
131
+ - ".github/FUNDING.yml"
104
132
  - ".gitignore"
105
133
  - ".rspec"
106
134
  - ".ruby-gemset"
@@ -111,19 +139,23 @@ files:
111
139
  - Gemfile.lock
112
140
  - MIT-LICENCE
113
141
  - README.md
142
+ - certs/mensfeld.pem
114
143
  - config/errors.yml
115
144
  - lib/water_drop.rb
116
145
  - lib/water_drop/async_producer.rb
117
146
  - lib/water_drop/base_producer.rb
118
147
  - lib/water_drop/config.rb
148
+ - lib/water_drop/config_applier.rb
149
+ - lib/water_drop/contracts.rb
150
+ - lib/water_drop/contracts/config.rb
151
+ - lib/water_drop/contracts/message_options.rb
119
152
  - lib/water_drop/errors.rb
120
- - lib/water_drop/instrumentation/listener.rb
121
153
  - lib/water_drop/instrumentation/monitor.rb
122
- - lib/water_drop/schemas/config.rb
123
- - lib/water_drop/schemas/message_options.rb
154
+ - lib/water_drop/instrumentation/stdout_listener.rb
124
155
  - lib/water_drop/sync_producer.rb
125
156
  - lib/water_drop/version.rb
126
157
  - lib/waterdrop.rb
158
+ - log/.keep
127
159
  - waterdrop.gemspec
128
160
  homepage: https://github.com/karafka/waterdrop
129
161
  licenses:
@@ -137,15 +169,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
169
  requirements:
138
170
  - - ">="
139
171
  - !ruby/object:Gem::Version
140
- version: 2.2.0
172
+ version: 2.4.0
141
173
  required_rubygems_version: !ruby/object:Gem::Requirement
142
174
  requirements:
143
175
  - - ">"
144
176
  - !ruby/object:Gem::Version
145
177
  version: 1.3.1
146
178
  requirements: []
147
- rubyforge_project:
148
- rubygems_version: 2.7.3
179
+ rubygems_version: 3.0.3
149
180
  signing_key:
150
181
  specification_version: 4
151
182
  summary: Kafka messaging made easy!
Binary file
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module WaterDrop
4
- # Namespace for all the schemas for config validations
5
- module Schemas
6
- # Schema with validation rules for WaterDrop configuration details
7
- Config = Dry::Validation.Schema do
8
- # Valid uri schemas of Kafka broker url
9
- URI_SCHEMES = %w[
10
- kafka
11
- kafka+ssl
12
- ].freeze
13
-
14
- # Available sasl scram mechanism of authentication (plus nil)
15
- SASL_SCRAM_MECHANISMS ||= %w[sha256 sha512].freeze
16
-
17
- configure do
18
- config.messages_file = File.join(
19
- WaterDrop.gem_root, 'config', 'errors.yml'
20
- )
21
-
22
- # Uri validator to check if uri is in a Kafka acceptable format
23
- # @param uri [String] uri we want to validate
24
- # @return [Boolean] true if it is a valid uri, otherwise false
25
- def broker_schema?(uri)
26
- uri = URI.parse(uri)
27
- URI_SCHEMES.include?(uri.scheme) && uri.port
28
- rescue URI::InvalidURIError
29
- false
30
- end
31
- end
32
-
33
- required(:client_id).filled(:str?, format?: Schemas::TOPIC_REGEXP)
34
- required(:logger).filled
35
- required(:deliver).filled(:bool?)
36
- required(:raise_on_buffer_overflow).filled(:bool?)
37
-
38
- required(:kafka).schema do
39
- required(:seed_brokers).filled { each(:broker_schema?) }
40
- required(:connect_timeout).filled { (int? | float?) & gt?(0) }
41
- required(:socket_timeout).filled { (int? | float?) & gt?(0) }
42
- required(:compression_threshold).filled(:int?, gteq?: 1)
43
- optional(:compression_codec).maybe(included_in?: %i[snappy gzip lz4])
44
-
45
- required(:max_buffer_bytesize).filled(:int?, gt?: 0)
46
- required(:max_buffer_size).filled(:int?, gt?: 0)
47
- required(:max_queue_size).filled(:int?, gt?: 0)
48
-
49
- required(:ack_timeout).filled(:int?, gt?: 0)
50
- required(:delivery_interval).filled(:int?, gteq?: 0)
51
- required(:delivery_threshold).filled(:int?, gteq?: 0)
52
-
53
- required(:max_retries).filled(:int?, gteq?: 0)
54
- required(:retry_backoff).filled(:int?, gteq?: 0)
55
- required(:required_acks).filled(included_in?: [1, 0, -1, :all])
56
-
57
- %i[
58
- ssl_ca_cert
59
- ssl_ca_cert_file_path
60
- ssl_client_cert
61
- ssl_client_cert_key
62
- sasl_gssapi_principal
63
- sasl_gssapi_keytab
64
- sasl_plain_authzid
65
- sasl_plain_username
66
- sasl_plain_password
67
- sasl_scram_username
68
- sasl_scram_password
69
- ].each do |encryption_attribute|
70
- optional(encryption_attribute).maybe(:str?)
71
- end
72
-
73
- optional(:ssl_ca_certs_from_system).maybe(:bool?)
74
-
75
- # It's not with other encryptions as it has some more rules
76
- optional(:sasl_scram_mechanism)
77
- .maybe(:str?, included_in?: WaterDrop::Schemas::SASL_SCRAM_MECHANISMS)
78
- end
79
- end
80
- end
81
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module WaterDrop
4
- module Schemas
5
- # Regexp to check that topic has a valid format
6
- TOPIC_REGEXP = /\A(\w|\-|\.)+\z/
7
-
8
- # Schema with validation rules for validating that all the message options that
9
- # we provide to producer ale valid and usable
10
- # @note Does not validate message itself as it is not our concern
11
- MessageOptions = Dry::Validation.Schema do
12
- required(:topic).filled(:str?, format?: TOPIC_REGEXP)
13
- optional(:key).maybe(:str?, :filled?)
14
- optional(:partition).filled(:int?, gteq?: 0)
15
- optional(:partition_key).maybe(:str?, :filled?)
16
- optional(:create_time).maybe(:time?)
17
- end
18
- end
19
- end