waterdrop 1.0.1 → 1.2.0.beta1
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/.ruby-version +1 -1
- data/.travis.yml +1 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +22 -11
- data/README.md +28 -34
- data/lib/water_drop.rb +9 -0
- data/lib/water_drop/async_producer.rb +8 -11
- data/lib/water_drop/base_producer.rb +29 -0
- data/lib/water_drop/config.rb +25 -8
- data/lib/water_drop/errors.rb +3 -0
- data/lib/water_drop/instrumentation/listener.rb +53 -0
- data/lib/water_drop/instrumentation/monitor.rb +47 -0
- data/lib/water_drop/schemas/config.rb +23 -14
- data/lib/water_drop/schemas/message_options.rb +1 -0
- data/lib/water_drop/sync_producer.rb +5 -10
- data/lib/water_drop/version.rb +1 -1
- data/waterdrop.gemspec +4 -3
- metadata +25 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 25c083d88a1163c685e9939307feba4294fd3a526f4523692958cdc5d0d04363
|
|
4
|
+
data.tar.gz: 300d3e1cce18970d0c9beb105ab6e3b6b7d5eedfc388e3fad7f1cd0db1c204e3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aa9f0cdfb2285b1f50a71f9a1e84310903e1abc936cd41838f8568a2ddf818b4c83324ccaf7a7c299980a7a8b7d6f0c8fb7fdad65b075e26440bc740be1f20cb
|
|
7
|
+
data.tar.gz: fff2c225e42eeb1ab849fb5ea34c900e6bf4b9783541a6087c094647ec8235c6ce6305087119455d2900cfd53c55e7179b27be5b0f29d49ef80f70720f6674ff
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.5.0
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# WaterDrop changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0.beta1
|
|
4
|
+
- #45 - Allow specifying a create time for messages
|
|
5
|
+
- #47 - Support SCRAM once released
|
|
6
|
+
- #49 - Add lz4 support once merged and released
|
|
7
|
+
- #50 - Potential message loss in async mode
|
|
8
|
+
- Ruby 2.5.0 support
|
|
9
|
+
- Gem bump to match Karafka framework versioning
|
|
10
|
+
- #48 - ssl_ca_certs_from_system
|
|
11
|
+
- #52 - Use instrumentation compatible with Karafka 1.2
|
|
12
|
+
|
|
3
13
|
## 1.0.1
|
|
4
14
|
- Added high level retry on connection problems
|
|
5
15
|
|
data/Gemfile.lock
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
waterdrop (1.0.
|
|
5
|
-
delivery_boy (>= 0.2.
|
|
4
|
+
waterdrop (1.2.0.beta1)
|
|
5
|
+
delivery_boy (>= 0.2.3)
|
|
6
6
|
dry-configurable (~> 0.7)
|
|
7
|
+
dry-monitor (~> 0.1)
|
|
7
8
|
dry-validation (~> 0.11)
|
|
8
9
|
null-logger
|
|
9
|
-
ruby-kafka (>= 0.5)
|
|
10
|
+
ruby-kafka (>= 0.5.3)
|
|
10
11
|
|
|
11
12
|
GEM
|
|
12
13
|
remote: https://rubygems.org/
|
|
13
14
|
specs:
|
|
14
15
|
concurrent-ruby (1.0.5)
|
|
15
|
-
delivery_boy (0.2.
|
|
16
|
+
delivery_boy (0.2.4)
|
|
16
17
|
king_konf (~> 0.1.8)
|
|
17
|
-
ruby-kafka (~> 0.
|
|
18
|
+
ruby-kafka (~> 0.5.1)
|
|
18
19
|
diff-lcs (1.3)
|
|
19
20
|
docile (1.1.5)
|
|
20
21
|
dry-configurable (0.7.0)
|
|
@@ -22,13 +23,22 @@ GEM
|
|
|
22
23
|
dry-container (0.6.0)
|
|
23
24
|
concurrent-ruby (~> 1.0)
|
|
24
25
|
dry-configurable (~> 0.1, >= 0.1.3)
|
|
25
|
-
dry-core (0.4.
|
|
26
|
+
dry-core (0.4.4)
|
|
26
27
|
concurrent-ruby (~> 1.0)
|
|
27
28
|
dry-equalizer (0.2.0)
|
|
29
|
+
dry-events (0.1.0)
|
|
30
|
+
concurrent-ruby (~> 1.0)
|
|
31
|
+
dry-core (~> 0.4)
|
|
32
|
+
dry-equalizer (~> 0.2)
|
|
28
33
|
dry-logic (0.4.2)
|
|
29
34
|
dry-container (~> 0.2, >= 0.2.6)
|
|
30
35
|
dry-core (~> 0.2)
|
|
31
36
|
dry-equalizer (~> 0.2)
|
|
37
|
+
dry-monitor (0.1.2)
|
|
38
|
+
dry-configurable (~> 0.5)
|
|
39
|
+
dry-equalizer (~> 0.2)
|
|
40
|
+
dry-events (~> 0.1)
|
|
41
|
+
rouge (~> 2.0, >= 2.2.1)
|
|
32
42
|
dry-types (0.12.2)
|
|
33
43
|
concurrent-ruby (~> 1.0)
|
|
34
44
|
dry-configurable (~> 0.1)
|
|
@@ -46,13 +56,14 @@ GEM
|
|
|
46
56
|
dry-types (~> 0.12.0)
|
|
47
57
|
inflecto (0.0.2)
|
|
48
58
|
json (2.1.0)
|
|
49
|
-
king_konf (0.1.
|
|
59
|
+
king_konf (0.1.10)
|
|
50
60
|
null-logger (0.1.4)
|
|
61
|
+
rouge (2.2.1)
|
|
51
62
|
rspec (3.7.0)
|
|
52
63
|
rspec-core (~> 3.7.0)
|
|
53
64
|
rspec-expectations (~> 3.7.0)
|
|
54
65
|
rspec-mocks (~> 3.7.0)
|
|
55
|
-
rspec-core (3.7.
|
|
66
|
+
rspec-core (3.7.1)
|
|
56
67
|
rspec-support (~> 3.7.0)
|
|
57
68
|
rspec-expectations (3.7.0)
|
|
58
69
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
@@ -60,8 +71,8 @@ GEM
|
|
|
60
71
|
rspec-mocks (3.7.0)
|
|
61
72
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
62
73
|
rspec-support (~> 3.7.0)
|
|
63
|
-
rspec-support (3.7.
|
|
64
|
-
ruby-kafka (0.5.
|
|
74
|
+
rspec-support (3.7.1)
|
|
75
|
+
ruby-kafka (0.5.3)
|
|
65
76
|
simplecov (0.15.1)
|
|
66
77
|
docile (~> 1.1.0)
|
|
67
78
|
json (>= 1.8, < 3)
|
|
@@ -77,4 +88,4 @@ DEPENDENCIES
|
|
|
77
88
|
waterdrop!
|
|
78
89
|
|
|
79
90
|
BUNDLED WITH
|
|
80
|
-
1.
|
|
91
|
+
1.16.1
|
data/README.md
CHANGED
|
@@ -11,6 +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
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -60,19 +61,20 @@ end
|
|
|
60
61
|
|
|
61
62
|
**Note:** All the options are subject to validations. In order to check what is and what is not acceptable, please go to the [config.rb validation schema](https://github.com/karafka/waterdrop/blob/master/lib/water_drop/schemas/config.rb) file.
|
|
62
63
|
|
|
63
|
-
| Option
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
64
|
+
| Option | Description |
|
|
65
|
+
|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
66
|
+
| raise_on_buffer_overflow | Should we raise an exception, when messages can't be sent in an async way due to the message buffer overflow or should we just drop them |
|
|
67
|
+
| delivery_interval | The number of seconds between background message deliveries. Disable timer-based background deliveries by setting this to 0. |
|
|
68
|
+
| delivery_threshold | The number of buffered messages that will trigger a background message delivery. Disable buffer size based background deliveries by setting this to 0.|
|
|
69
|
+
| required_acks | The number of Kafka replicas that must acknowledge messages before they're considered as successfully written. |
|
|
70
|
+
| ack_timeout | A timeout executed by a broker when the client is sending messages to it. |
|
|
71
|
+
| max_retries | The number of retries when attempting to deliver messages. |
|
|
72
|
+
| retry_backoff | The number of seconds to wait after a failed attempt to send messages to a Kafka broker before retrying. |
|
|
73
|
+
| max_buffer_bytesize | The maximum number of bytes allowed in the buffer before new messages are rejected. |
|
|
74
|
+
| max_buffer_size | The maximum number of messages allowed in the buffer before new messages are rejected. |
|
|
75
|
+
| max_queue_size | The maximum number of messages allowed in the queue before new messages are rejected. |
|
|
76
|
+
| sasl_plain_username | The username used to authenticate. |
|
|
77
|
+
| sasl_plain_password | The password used to authenticate. |
|
|
76
78
|
|
|
77
79
|
This configuration can be also placed in *config/initializers* and can vary based on the environment:
|
|
78
80
|
|
|
@@ -95,12 +97,13 @@ WaterDrop::AsyncProducer.call('message', topic: 'my-topic')
|
|
|
95
97
|
|
|
96
98
|
Both ```SyncProducer``` and ```AsyncProducer``` accept following options:
|
|
97
99
|
|
|
98
|
-
| Option | Required | Value type
|
|
99
|
-
|--------------------
|
|
100
|
-
| ```topic``` | true | String
|
|
101
|
-
| ```key``` | false | String
|
|
102
|
-
| ```partition``` | false | Integer
|
|
103
|
-
| ```partition_key``` | false | String
|
|
100
|
+
| Option | Required | Value type | Description |
|
|
101
|
+
|-------------------- |----------|------------|---------------------------------------------------------------------|
|
|
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 |
|
|
104
|
+
| ```partition``` | false | Integer | A specific partition number that should be written to |
|
|
105
|
+
| ```partition_key``` | false | String | A string that can be used to deterministically select the partition |
|
|
106
|
+
| ```create_time``` | false | Time | The timestamp that should be set on the message |
|
|
104
107
|
|
|
105
108
|
Keep in mind, that message you want to send should be either binary or stringified (to_s, to_json, etc).
|
|
106
109
|
|
|
@@ -110,23 +113,14 @@ Keep in mind, that message you want to send should be either binary or stringifi
|
|
|
110
113
|
* [WaterDrop Travis CI](https://travis-ci.org/karafka/waterdrop)
|
|
111
114
|
* [WaterDrop Coditsu](https://app.coditsu.io/karafka/repositories/waterdrop)
|
|
112
115
|
|
|
113
|
-
## Note on
|
|
116
|
+
## Note on contributions
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
Make your feature addition or bug fix.
|
|
117
|
-
Add tests for it. This is important so we don't break it in a future versions unintentionally.
|
|
118
|
-
Commit, do not mess with version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull). Send me a pull request. Bonus points for topic branches.
|
|
118
|
+
First, thank you for considering contributing to WaterDrop! It's people like you that make the open source community such a great community!
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
Each pull request must pass all the rspec specs and meet our quality requirements.
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
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
123
|
|
|
124
|
-
|
|
124
|
+
Coditsu will automatically check your work against our quality standards. You can find your commit check results on the [builds page](https://app.coditsu.io/karafka/repositories/waterdrop/builds/commit_builds) of WaterDrop repository.
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
bundle exec rspec
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
to check if everything is in order. After that you can submit a pull request.
|
|
126
|
+
[](https://app.coditsu.io/karafka/repositories/waterdrop/builds/commit_builds)
|
data/lib/water_drop.rb
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
json
|
|
6
6
|
delivery_boy
|
|
7
7
|
null_logger
|
|
8
|
+
singleton
|
|
8
9
|
dry-configurable
|
|
10
|
+
dry/monitor/notifications
|
|
9
11
|
dry-validation
|
|
10
12
|
].each { |lib| require lib }
|
|
11
13
|
|
|
@@ -44,6 +46,11 @@ module WaterDrop
|
|
|
44
46
|
Config.config
|
|
45
47
|
end
|
|
46
48
|
|
|
49
|
+
# @return [::WaterDrop::Monitor] monitor that we want to use
|
|
50
|
+
def monitor
|
|
51
|
+
config.monitor
|
|
52
|
+
end
|
|
53
|
+
|
|
47
54
|
# @return [String] root path of this gem
|
|
48
55
|
def gem_root
|
|
49
56
|
Pathname.new(File.expand_path('../..', __FILE__))
|
|
@@ -53,6 +60,8 @@ end
|
|
|
53
60
|
|
|
54
61
|
%w[
|
|
55
62
|
version
|
|
63
|
+
instrumentation/monitor
|
|
64
|
+
instrumentation/listener
|
|
56
65
|
schemas/message_options
|
|
57
66
|
schemas/config
|
|
58
67
|
config
|
|
@@ -10,20 +10,17 @@ module WaterDrop
|
|
|
10
10
|
# @raise [WaterDrop::Errors::InvalidMessageOptions] raised when message options are
|
|
11
11
|
# somehow invalid and we cannot perform delivery because of that
|
|
12
12
|
def self.call(message, options)
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
attempts_count ||= 0
|
|
14
|
+
attempts_count += 1
|
|
15
15
|
|
|
16
16
|
validate!(options)
|
|
17
17
|
return unless WaterDrop.config.deliver
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
WaterDrop.logger.warn "Retrying delivery after: #{e}"
|
|
25
|
-
retry
|
|
26
|
-
end
|
|
18
|
+
|
|
19
|
+
d_method = WaterDrop.config.raise_on_buffer_overflow ? :deliver_async! : :deliver_async
|
|
20
|
+
|
|
21
|
+
DeliveryBoy.send(d_method, message, options)
|
|
22
|
+
rescue Kafka::Error => error
|
|
23
|
+
graceful_attempt?(attempts_count, message, options, error) ? retry : raise(error)
|
|
27
24
|
end
|
|
28
25
|
end
|
|
29
26
|
end
|
|
@@ -16,6 +16,35 @@ module WaterDrop
|
|
|
16
16
|
return true if validation_result.success?
|
|
17
17
|
raise Errors::InvalidMessageOptions, validation_result.errors
|
|
18
18
|
end
|
|
19
|
+
|
|
20
|
+
# 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
|
|
22
|
+
# This method checks that and also instruments errors and retries for the delivery
|
|
23
|
+
# @param attempts_count [Integer] number of attempt (starting from 1) for the delivery
|
|
24
|
+
# @param message [String] message that we want to send to Kafka
|
|
25
|
+
# @param options [Hash] options (including topic) for producer
|
|
26
|
+
# @param error [Kafka::Error] error that occured
|
|
27
|
+
# @return [Boolean] true if this is a graceful attempt and we can retry or false it this
|
|
28
|
+
# was the final one and we should deal with the fact, that we cannot deliver a given
|
|
29
|
+
# message
|
|
30
|
+
def graceful_attempt?(attempts_count, message, options, error)
|
|
31
|
+
scope = "#{to_s.split('::').last.sub('Producer', '_producer').downcase}.call"
|
|
32
|
+
payload = {
|
|
33
|
+
caller: self,
|
|
34
|
+
message: message,
|
|
35
|
+
options: options,
|
|
36
|
+
error: error,
|
|
37
|
+
attempts_count: attempts_count
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if attempts_count > WaterDrop.config.kafka.max_retries
|
|
41
|
+
WaterDrop.monitor.instrument("#{scope}.error", payload)
|
|
42
|
+
false
|
|
43
|
+
else
|
|
44
|
+
WaterDrop.monitor.instrument("#{scope}.retry", payload)
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
19
48
|
end
|
|
20
49
|
end
|
|
21
50
|
end
|
data/lib/water_drop/config.rb
CHANGED
|
@@ -12,9 +12,17 @@ module WaterDrop
|
|
|
12
12
|
setting :client_id, 'waterdrop'
|
|
13
13
|
# option [Instance, nil] logger that we want to use or nil to fallback to ruby-kafka logger
|
|
14
14
|
setting :logger, NullLogger.new
|
|
15
|
+
# option [Instance] monitor that we want to use. See instrumentation part of the README for
|
|
16
|
+
# more details
|
|
17
|
+
setting :monitor, WaterDrop::Instrumentation::Monitor.instance
|
|
15
18
|
# option [Boolean] should we send messages. Setting this to false can be really useful when
|
|
16
19
|
# testing and or developing because when set to false, won't actually ping Kafka
|
|
17
20
|
setting :deliver, true
|
|
21
|
+
# option [Boolean] if you're producing messages faster than the framework or the network can
|
|
22
|
+
# send them off, ruby-kafka might reject them. If that happens, WaterDrop will either raise
|
|
23
|
+
# or ignore - this setting manages that behavior. This only applies to async producer as
|
|
24
|
+
# sync producer will always raise upon problems
|
|
25
|
+
setting :raise_on_buffer_overflow, true
|
|
18
26
|
|
|
19
27
|
# Settings directly related to the Kafka driver
|
|
20
28
|
setting :kafka do
|
|
@@ -73,24 +81,33 @@ module WaterDrop
|
|
|
73
81
|
setting :compression_codec, nil
|
|
74
82
|
|
|
75
83
|
# SSL authentication related settings
|
|
76
|
-
# option ca_cert [String] SSL CA certificate
|
|
84
|
+
# option ca_cert [String, nil] SSL CA certificate
|
|
77
85
|
setting :ssl_ca_cert, nil
|
|
78
|
-
# option ssl_ca_cert_file_path [String] SSL CA certificate file path
|
|
86
|
+
# option ssl_ca_cert_file_path [String, nil] SSL CA certificate file path
|
|
79
87
|
setting :ssl_ca_cert_file_path, nil
|
|
80
|
-
# option
|
|
88
|
+
# option ssl_ca_certs_from_system [Boolean] Use the CA certs from your system's default
|
|
89
|
+
# certificate store
|
|
90
|
+
setting :ssl_ca_certs_from_system, false
|
|
91
|
+
# option ssl_client_cert [String, nil] SSL client certificate
|
|
81
92
|
setting :ssl_client_cert, nil
|
|
82
|
-
# option ssl_client_cert_key [String] SSL client certificate password
|
|
93
|
+
# option ssl_client_cert_key [String, nil] SSL client certificate password
|
|
83
94
|
setting :ssl_client_cert_key, nil
|
|
84
|
-
# option sasl_gssapi_principal [String] sasl principal
|
|
95
|
+
# option sasl_gssapi_principal [String, nil] sasl principal
|
|
85
96
|
setting :sasl_gssapi_principal, nil
|
|
86
|
-
# option sasl_gssapi_keytab [String] sasl keytab
|
|
97
|
+
# option sasl_gssapi_keytab [String, nil] sasl keytab
|
|
87
98
|
setting :sasl_gssapi_keytab, nil
|
|
88
99
|
# option sasl_plain_authzid [String] The authorization identity to use
|
|
89
100
|
setting :sasl_plain_authzid, ''
|
|
90
|
-
# option sasl_plain_username [String] The username used to authenticate
|
|
101
|
+
# option sasl_plain_username [String, nil] The username used to authenticate
|
|
91
102
|
setting :sasl_plain_username, nil
|
|
92
|
-
# option sasl_plain_password [String] The password used to authenticate
|
|
103
|
+
# option sasl_plain_password [String, nil] The password used to authenticate
|
|
93
104
|
setting :sasl_plain_password, nil
|
|
105
|
+
# option sasl_scram_username [String, nil] The username used to authenticate
|
|
106
|
+
setting :sasl_scram_username, nil
|
|
107
|
+
# option sasl_scram_password [String, nil] The password used to authenticate
|
|
108
|
+
setting :sasl_scram_password, nil
|
|
109
|
+
# option sasl_scram_mechanism [String, nil] Scram mechanism, either 'sha256' or 'sha512'
|
|
110
|
+
setting :sasl_scram_mechanism, nil
|
|
94
111
|
end
|
|
95
112
|
|
|
96
113
|
# option producer [Hash] - optional - producer configuration options
|
data/lib/water_drop/errors.rb
CHANGED
|
@@ -11,5 +11,8 @@ module WaterDrop
|
|
|
11
11
|
|
|
12
12
|
# Raised when we try to send message with invalid optionss
|
|
13
13
|
InvalidMessageOptions = Class.new(BaseError)
|
|
14
|
+
|
|
15
|
+
# Raised when want to hook up to an event that is not registered and supported
|
|
16
|
+
UnregisteredMonitorEvent = Class.new(BaseError)
|
|
14
17
|
end
|
|
15
18
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WaterDrop
|
|
4
|
+
module Instrumentation
|
|
5
|
+
# Default listener that hooks up to our instrumentation and uses its events for logging
|
|
6
|
+
# It can be removed/replaced or anything without any harm to the Waterdrop flow
|
|
7
|
+
# @note It is a module as we can use it then as a part of the Karafka framework listener
|
|
8
|
+
# as well as we can use it standalone
|
|
9
|
+
module Listener
|
|
10
|
+
# Log levels that we use in this particular listener
|
|
11
|
+
USED_LOG_LEVELS = %i[
|
|
12
|
+
info
|
|
13
|
+
error
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
%i[
|
|
17
|
+
sync_producer
|
|
18
|
+
async_producer
|
|
19
|
+
].each do |producer_type|
|
|
20
|
+
error_name = :"on_#{producer_type}_call_error"
|
|
21
|
+
retry_name = :"on_#{producer_type}_call_retry"
|
|
22
|
+
|
|
23
|
+
define_method error_name do |event|
|
|
24
|
+
options = event[:options]
|
|
25
|
+
error = event[:error]
|
|
26
|
+
error "Delivery failure to: #{options} because of #{error}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
define_method retry_name do |event|
|
|
30
|
+
attempts_count = event[:attempts_count]
|
|
31
|
+
options = event[:options]
|
|
32
|
+
error = event[:error]
|
|
33
|
+
|
|
34
|
+
info "Attempt #{attempts_count} of delivery to: #{options} because of #{error}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module_function error_name
|
|
38
|
+
module_function retry_name
|
|
39
|
+
public error_name
|
|
40
|
+
public retry_name
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
USED_LOG_LEVELS.each do |log_level|
|
|
44
|
+
define_method log_level do |*args|
|
|
45
|
+
WaterDrop.logger.send(log_level, *args)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module_function log_level
|
|
49
|
+
private_class_method log_level
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WaterDrop
|
|
4
|
+
# Namespace for all the things related with WaterDrop instrumentation process
|
|
5
|
+
module Instrumentation
|
|
6
|
+
# Monitor is used to hookup external monitoring services to monitor how WaterDrop works
|
|
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
|
|
9
|
+
# time
|
|
10
|
+
# @note This class acts as a singleton because we are only permitted to have single monitor
|
|
11
|
+
# per running process (just as logger)
|
|
12
|
+
class Monitor < Dry::Monitor::Notifications
|
|
13
|
+
include Singleton
|
|
14
|
+
|
|
15
|
+
# List of events that we support in the system and to which a monitor client can hook up
|
|
16
|
+
# @note The non-error once support timestamp benchmarking
|
|
17
|
+
BASE_EVENTS = %w[
|
|
18
|
+
async_producer.call.error
|
|
19
|
+
async_producer.call.retry
|
|
20
|
+
sync_producer.call.error
|
|
21
|
+
sync_producer.call.retry
|
|
22
|
+
].freeze
|
|
23
|
+
|
|
24
|
+
private_constant :BASE_EVENTS
|
|
25
|
+
|
|
26
|
+
# @return [WaterDrop::Instrumentation::Monitor] monitor instance for system instrumentation
|
|
27
|
+
def initialize
|
|
28
|
+
super(:waterdrop)
|
|
29
|
+
BASE_EVENTS.each(&method(:register_event))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Allows us to subscribe to events with a code that will be yielded upon events
|
|
33
|
+
# @param event_name_or_listener [String, Object] name of the event we want to subscribe to
|
|
34
|
+
# or a listener if we decide to go with object listener
|
|
35
|
+
def subscribe(event_name_or_listener)
|
|
36
|
+
return super unless event_name_or_listener.is_a?(String)
|
|
37
|
+
return super if available_events.include?(event_name_or_listener)
|
|
38
|
+
raise Errors::UnregisteredMonitorEvent, event_name_or_listener
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return [Array<String>] names of available events to which we can subscribe
|
|
42
|
+
def available_events
|
|
43
|
+
__bus__.events.keys
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -11,18 +11,8 @@ module WaterDrop
|
|
|
11
11
|
kafka+ssl
|
|
12
12
|
].freeze
|
|
13
13
|
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
ssl_ca_cert
|
|
17
|
-
ssl_ca_cert_file_path
|
|
18
|
-
ssl_client_cert
|
|
19
|
-
ssl_client_cert_key
|
|
20
|
-
sasl_plain_authzid
|
|
21
|
-
sasl_plain_username
|
|
22
|
-
sasl_plain_password
|
|
23
|
-
sasl_gssapi_principal
|
|
24
|
-
sasl_gssapi_keytab
|
|
25
|
-
].freeze
|
|
14
|
+
# Available sasl scram mechanism of authentication (plus nil)
|
|
15
|
+
SASL_SCRAM_MECHANISMS ||= %w[sha256 sha512].freeze
|
|
26
16
|
|
|
27
17
|
configure do
|
|
28
18
|
config.messages_file = File.join(
|
|
@@ -43,13 +33,14 @@ module WaterDrop
|
|
|
43
33
|
required(:client_id).filled(:str?, format?: Schemas::TOPIC_REGEXP)
|
|
44
34
|
required(:logger).filled
|
|
45
35
|
required(:deliver).filled(:bool?)
|
|
36
|
+
required(:raise_on_buffer_overflow).filled(:bool?)
|
|
46
37
|
|
|
47
38
|
required(:kafka).schema do
|
|
48
39
|
required(:seed_brokers).filled { each(:broker_schema?) }
|
|
49
40
|
required(:connect_timeout).filled { (int? | float?) & gt?(0) }
|
|
50
41
|
required(:socket_timeout).filled { (int? | float?) & gt?(0) }
|
|
51
42
|
required(:compression_threshold).filled(:int?, gteq?: 1)
|
|
52
|
-
optional(:compression_codec).maybe(included_in?: %i[snappy gzip])
|
|
43
|
+
optional(:compression_codec).maybe(included_in?: %i[snappy gzip lz4])
|
|
53
44
|
|
|
54
45
|
required(:max_buffer_bytesize).filled(:int?, gt?: 0)
|
|
55
46
|
required(:max_buffer_size).filled(:int?, gt?: 0)
|
|
@@ -63,9 +54,27 @@ module WaterDrop
|
|
|
63
54
|
required(:retry_backoff).filled(:int?, gteq?: 0)
|
|
64
55
|
required(:required_acks).filled(included_in?: [1, 0, -1, :all])
|
|
65
56
|
|
|
66
|
-
|
|
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|
|
|
67
70
|
optional(encryption_attribute).maybe(:str?)
|
|
68
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)
|
|
69
78
|
end
|
|
70
79
|
end
|
|
71
80
|
end
|
|
@@ -10,20 +10,15 @@ module WaterDrop
|
|
|
10
10
|
# @raise [WaterDrop::Errors::InvalidMessageOptions] raised when message options are
|
|
11
11
|
# somehow invalid and we cannot perform delivery because of that
|
|
12
12
|
def self.call(message, options)
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
attempts_count ||= 0
|
|
14
|
+
attempts_count += 1
|
|
15
15
|
|
|
16
16
|
validate!(options)
|
|
17
17
|
return unless WaterDrop.config.deliver
|
|
18
|
+
|
|
18
19
|
DeliveryBoy.deliver(message, options)
|
|
19
|
-
rescue Kafka::Error =>
|
|
20
|
-
|
|
21
|
-
WaterDrop.logger.error e
|
|
22
|
-
raise e
|
|
23
|
-
else
|
|
24
|
-
WaterDrop.logger.warn "Retrying delivery after: #{e}"
|
|
25
|
-
retry
|
|
26
|
-
end
|
|
20
|
+
rescue Kafka::Error => error
|
|
21
|
+
graceful_attempt?(attempts_count, message, options, error) ? retry : raise(error)
|
|
27
22
|
end
|
|
28
23
|
end
|
|
29
24
|
end
|
data/lib/water_drop/version.rb
CHANGED
data/waterdrop.gemspec
CHANGED
|
@@ -12,15 +12,16 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.authors = ['Maciej Mensfeld']
|
|
13
13
|
spec.email = %w[maciej@mensfeld.pl]
|
|
14
14
|
spec.homepage = 'https://github.com/karafka/waterdrop'
|
|
15
|
-
spec.summary = '
|
|
15
|
+
spec.summary = 'Kafka messaging made easy!'
|
|
16
16
|
spec.description = spec.summary
|
|
17
17
|
spec.license = 'MIT'
|
|
18
18
|
|
|
19
|
-
spec.add_dependency 'delivery_boy', '>= 0.2.
|
|
19
|
+
spec.add_dependency 'delivery_boy', '>= 0.2.3'
|
|
20
20
|
spec.add_dependency 'dry-configurable', '~> 0.7'
|
|
21
|
+
spec.add_dependency 'dry-monitor', '~> 0.1'
|
|
21
22
|
spec.add_dependency 'dry-validation', '~> 0.11'
|
|
22
23
|
spec.add_dependency 'null-logger'
|
|
23
|
-
spec.add_dependency 'ruby-kafka', '>= 0.5'
|
|
24
|
+
spec.add_dependency 'ruby-kafka', '>= 0.5.3'
|
|
24
25
|
|
|
25
26
|
spec.required_ruby_version = '>= 2.2.0'
|
|
26
27
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: waterdrop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.2.0.beta1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Maciej Mensfeld
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2018-02-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: delivery_boy
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.2.
|
|
19
|
+
version: 0.2.3
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.2.
|
|
26
|
+
version: 0.2.3
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: dry-configurable
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -38,6 +38,20 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0.7'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: dry-monitor
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.1'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.1'
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: dry-validation
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,14 +86,14 @@ dependencies:
|
|
|
72
86
|
requirements:
|
|
73
87
|
- - ">="
|
|
74
88
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
89
|
+
version: 0.5.3
|
|
76
90
|
type: :runtime
|
|
77
91
|
prerelease: false
|
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
93
|
requirements:
|
|
80
94
|
- - ">="
|
|
81
95
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
96
|
+
version: 0.5.3
|
|
83
97
|
description: Kafka messaging made easy!
|
|
84
98
|
email:
|
|
85
99
|
- maciej@mensfeld.pl
|
|
@@ -103,6 +117,8 @@ files:
|
|
|
103
117
|
- lib/water_drop/base_producer.rb
|
|
104
118
|
- lib/water_drop/config.rb
|
|
105
119
|
- lib/water_drop/errors.rb
|
|
120
|
+
- lib/water_drop/instrumentation/listener.rb
|
|
121
|
+
- lib/water_drop/instrumentation/monitor.rb
|
|
106
122
|
- lib/water_drop/schemas/config.rb
|
|
107
123
|
- lib/water_drop/schemas/message_options.rb
|
|
108
124
|
- lib/water_drop/sync_producer.rb
|
|
@@ -124,12 +140,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
124
140
|
version: 2.2.0
|
|
125
141
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
142
|
requirements:
|
|
127
|
-
- - "
|
|
143
|
+
- - ">"
|
|
128
144
|
- !ruby/object:Gem::Version
|
|
129
|
-
version:
|
|
145
|
+
version: 1.3.1
|
|
130
146
|
requirements: []
|
|
131
147
|
rubyforge_project:
|
|
132
|
-
rubygems_version: 2.
|
|
148
|
+
rubygems_version: 2.7.3
|
|
133
149
|
signing_key:
|
|
134
150
|
specification_version: 4
|
|
135
151
|
summary: Kafka messaging made easy!
|