waterdrop 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.coditsu/ci.yml +3 -0
- data/.github/FUNDING.yml +1 -0
- data/.gitignore +68 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +35 -0
- data/CHANGELOG.md +158 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +102 -0
- data/MIT-LICENCE +18 -0
- data/README.md +127 -0
- data/certs/mensfeld.pem +25 -0
- data/config/errors.yml +19 -0
- data/lib/water_drop.rb +50 -0
- data/lib/water_drop/async_producer.rb +26 -0
- data/lib/water_drop/base_producer.rb +57 -0
- data/lib/water_drop/config.rb +162 -0
- data/lib/water_drop/config_applier.rb +52 -0
- data/lib/water_drop/contracts.rb +9 -0
- data/lib/water_drop/contracts/config.rb +139 -0
- data/lib/water_drop/contracts/message_options.rb +19 -0
- data/lib/water_drop/errors.rb +18 -0
- data/lib/water_drop/instrumentation/monitor.rb +46 -0
- data/lib/water_drop/instrumentation/stdout_listener.rb +45 -0
- data/lib/water_drop/sync_producer.rb +24 -0
- data/lib/water_drop/version.rb +7 -0
- data/lib/waterdrop.rb +4 -0
- data/log/.gitkeep +0 -0
- data/waterdrop.gemspec +36 -0
- metadata +189 -0
- metadata.gz.sig +0 -0
@@ -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
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WaterDrop
|
4
|
+
# Namespace used to encapsulate all the internal errors of WaterDrop
|
5
|
+
module Errors
|
6
|
+
# Base class for all the WaterDrop internal errors
|
7
|
+
BaseError = Class.new(StandardError)
|
8
|
+
|
9
|
+
# Raised when configuration doesn't match with validation contract
|
10
|
+
InvalidConfiguration = Class.new(BaseError)
|
11
|
+
|
12
|
+
# Raised when we try to send message with invalid options
|
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)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
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
|
+
# List of events that we support in the system and to which a monitor client can hook up
|
14
|
+
# @note The non-error once support timestamp benchmarking
|
15
|
+
BASE_EVENTS = %w[
|
16
|
+
async_producer.call.error
|
17
|
+
async_producer.call.retry
|
18
|
+
sync_producer.call.error
|
19
|
+
sync_producer.call.retry
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
private_constant :BASE_EVENTS
|
23
|
+
|
24
|
+
# @return [WaterDrop::Instrumentation::Monitor] monitor instance for system instrumentation
|
25
|
+
def initialize
|
26
|
+
super(:waterdrop)
|
27
|
+
BASE_EVENTS.each(&method(:register_event))
|
28
|
+
end
|
29
|
+
|
30
|
+
# Allows us to subscribe to events with a code that will be yielded upon events
|
31
|
+
# @param event_name_or_listener [String, Object] name of the event we want to subscribe to
|
32
|
+
# or a listener if we decide to go with object listener
|
33
|
+
def subscribe(event_name_or_listener)
|
34
|
+
return super unless event_name_or_listener.is_a?(String)
|
35
|
+
return super if available_events.include?(event_name_or_listener)
|
36
|
+
|
37
|
+
raise Errors::UnregisteredMonitorEvent, event_name_or_listener
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Array<String>] names of available events to which we can subscribe
|
41
|
+
def available_events
|
42
|
+
__bus__.events.keys
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,45 @@
|
|
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
|
+
class StdoutListener
|
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
|
+
end
|
37
|
+
|
38
|
+
USED_LOG_LEVELS.each do |log_level|
|
39
|
+
define_method log_level do |*args|
|
40
|
+
WaterDrop.logger.send(log_level, *args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# WaterDrop library
|
4
|
+
module WaterDrop
|
5
|
+
# Sync producer for messages
|
6
|
+
class SyncProducer < BaseProducer
|
7
|
+
# Performs message delivery using deliver_async method
|
8
|
+
# @param message [String] message that we want to send to Kafka
|
9
|
+
# @param options [Hash] options (including topic) for producer
|
10
|
+
# @raise [WaterDrop::Errors::InvalidMessageOptions] raised when message options are
|
11
|
+
# somehow invalid and we cannot perform delivery because of that
|
12
|
+
def self.call(message, options)
|
13
|
+
attempts_count ||= 0
|
14
|
+
attempts_count += 1
|
15
|
+
|
16
|
+
validate!(options)
|
17
|
+
return unless WaterDrop.config.deliver
|
18
|
+
|
19
|
+
DeliveryBoy.deliver(message, options)
|
20
|
+
rescue Kafka::Error => e
|
21
|
+
graceful_attempt?(attempts_count, message, options, e) ? retry : raise(e)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/waterdrop.rb
ADDED
data/log/.gitkeep
ADDED
File without changes
|
data/waterdrop.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'water_drop/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'waterdrop'
|
10
|
+
spec.version = ::WaterDrop::VERSION
|
11
|
+
spec.platform = Gem::Platform::RUBY
|
12
|
+
spec.authors = ['Maciej Mensfeld']
|
13
|
+
spec.email = %w[maciej@mensfeld.pl]
|
14
|
+
spec.homepage = 'https://github.com/karafka/waterdrop'
|
15
|
+
spec.summary = 'Kafka messaging made easy!'
|
16
|
+
spec.description = spec.summary
|
17
|
+
spec.license = 'MIT'
|
18
|
+
|
19
|
+
spec.add_dependency 'delivery_boy', '>= 0.2', '< 2.x'
|
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
|
+
|
26
|
+
spec.required_ruby_version = '>= 2.5.0'
|
27
|
+
|
28
|
+
if $PROGRAM_NAME.end_with?('gem')
|
29
|
+
spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem')
|
30
|
+
end
|
31
|
+
|
32
|
+
spec.cert_chain = %w[certs/mensfeld.pem]
|
33
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
|
34
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
35
|
+
spec.require_paths = %w[lib]
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: waterdrop
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Maciej Mensfeld
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhtYWNp
|
14
|
+
ZWovREM9bWVuc2ZlbGQvREM9cGwwHhcNMjAwODExMDkxNTM3WhcNMjEwODExMDkx
|
15
|
+
NTM3WjAjMSEwHwYDVQQDDBhtYWNpZWovREM9bWVuc2ZlbGQvREM9cGwwggGiMA0G
|
16
|
+
CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDCpXsCgmINb6lHBXXBdyrgsBPSxC4/
|
17
|
+
2H+weJ6L9CruTiv2+2/ZkQGtnLcDgrD14rdLIHK7t0o3EKYlDT5GhD/XUVhI15JE
|
18
|
+
N7IqnPUgexe1fbZArwQ51afxz2AmPQN2BkB2oeQHXxnSWUGMhvcEZpfbxCCJH26w
|
19
|
+
hS0Ccsma8yxA6hSlGVhFVDuCr7c2L1di6cK2CtIDpfDaWqnVNJEwBYHIxrCoWK5g
|
20
|
+
sIGekVt/admS9gRhIMaIBg+Mshth5/DEyWO2QjteTodItlxfTctrfmiAl8X8T5JP
|
21
|
+
VXeLp5SSOJ5JXE80nShMJp3RFnGw5fqjX/ffjtISYh78/By4xF3a25HdWH9+qO2Z
|
22
|
+
tx0wSGc9/4gqNM0APQnjN/4YXrGZ4IeSjtE+OrrX07l0TiyikzSLFOkZCAp8oBJi
|
23
|
+
Fhlosz8xQDJf7mhNxOaZziqASzp/hJTU/tuDKl5+ql2icnMv5iV/i6SlmvU29QNg
|
24
|
+
LCV71pUv0pWzN+OZbHZKWepGhEQ3cG9MwvkCAwEAAaN3MHUwCQYDVR0TBAIwADAL
|
25
|
+
BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFImGed2AXS070ohfRidiCEhXEUN+MB0GA1Ud
|
26
|
+
EQQWMBSBEm1hY2llakBtZW5zZmVsZC5wbDAdBgNVHRIEFjAUgRJtYWNpZWpAbWVu
|
27
|
+
c2ZlbGQucGwwDQYJKoZIhvcNAQELBQADggGBAKiHpwoENVrMi94V1zD4o8/6G3AU
|
28
|
+
gWz4udkPYHTZLUy3dLznc/sNjdkJFWT3E6NKYq7c60EpJ0m0vAEg5+F5pmNOsvD3
|
29
|
+
2pXLj9kisEeYhR516HwXAvtngboUcb75skqvBCU++4Pu7BRAPjO1/ihLSBexbwSS
|
30
|
+
fF+J5OWNuyHHCQp+kGPLtXJe2yUYyvSWDj3I2//Vk0VhNOIlaCS1+5/P3ZJThOtm
|
31
|
+
zJUBI7h3HgovwRpcnmk2mXTmU4Zx/bCzX8EA6VY0khEvnmiq7S6eBF0H9qH8KyQ6
|
32
|
+
EkVLpvmUDFcf/uNaBQdazEMB5jYtwoA8gQlANETNGPi51KlkukhKgaIEDMkBDJOx
|
33
|
+
65N7DzmkcyY0/GwjIVIxmRhcrCt1YeCUElmfFx0iida1/YRm6sB2AXqScc1+ECRi
|
34
|
+
2DND//YJUikn1zwbz1kT70XmHd97B4Eytpln7K+M1u2g1pHVEPW4owD/ammXNpUy
|
35
|
+
nt70FcDD4yxJQ+0YNiHd0N8IcVBM1TMIVctMNQ==
|
36
|
+
-----END CERTIFICATE-----
|
37
|
+
date: 2020-08-25 00:00:00.000000000 Z
|
38
|
+
dependencies:
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: delivery_boy
|
41
|
+
requirement: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0.2'
|
46
|
+
- - "<"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 2.x
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0.2'
|
56
|
+
- - "<"
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 2.x
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: dry-configurable
|
61
|
+
requirement: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - "~>"
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0.8'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - "~>"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0.8'
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: dry-monitor
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0.3'
|
80
|
+
type: :runtime
|
81
|
+
prerelease: false
|
82
|
+
version_requirements: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - "~>"
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0.3'
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
name: dry-validation
|
89
|
+
requirement: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - "~>"
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1.2'
|
94
|
+
type: :runtime
|
95
|
+
prerelease: false
|
96
|
+
version_requirements: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - "~>"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '1.2'
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
name: ruby-kafka
|
103
|
+
requirement: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: 0.7.8
|
108
|
+
type: :runtime
|
109
|
+
prerelease: false
|
110
|
+
version_requirements: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: 0.7.8
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: zeitwerk
|
117
|
+
requirement: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - "~>"
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '2.1'
|
122
|
+
type: :runtime
|
123
|
+
prerelease: false
|
124
|
+
version_requirements: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - "~>"
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '2.1'
|
129
|
+
description: Kafka messaging made easy!
|
130
|
+
email:
|
131
|
+
- maciej@mensfeld.pl
|
132
|
+
executables: []
|
133
|
+
extensions: []
|
134
|
+
extra_rdoc_files: []
|
135
|
+
files:
|
136
|
+
- ".coditsu/ci.yml"
|
137
|
+
- ".github/FUNDING.yml"
|
138
|
+
- ".gitignore"
|
139
|
+
- ".rspec"
|
140
|
+
- ".ruby-gemset"
|
141
|
+
- ".ruby-version"
|
142
|
+
- ".travis.yml"
|
143
|
+
- CHANGELOG.md
|
144
|
+
- Gemfile
|
145
|
+
- Gemfile.lock
|
146
|
+
- MIT-LICENCE
|
147
|
+
- README.md
|
148
|
+
- certs/mensfeld.pem
|
149
|
+
- config/errors.yml
|
150
|
+
- lib/water_drop.rb
|
151
|
+
- lib/water_drop/async_producer.rb
|
152
|
+
- lib/water_drop/base_producer.rb
|
153
|
+
- lib/water_drop/config.rb
|
154
|
+
- lib/water_drop/config_applier.rb
|
155
|
+
- lib/water_drop/contracts.rb
|
156
|
+
- lib/water_drop/contracts/config.rb
|
157
|
+
- lib/water_drop/contracts/message_options.rb
|
158
|
+
- lib/water_drop/errors.rb
|
159
|
+
- lib/water_drop/instrumentation/monitor.rb
|
160
|
+
- lib/water_drop/instrumentation/stdout_listener.rb
|
161
|
+
- lib/water_drop/sync_producer.rb
|
162
|
+
- lib/water_drop/version.rb
|
163
|
+
- lib/waterdrop.rb
|
164
|
+
- log/.gitkeep
|
165
|
+
- waterdrop.gemspec
|
166
|
+
homepage: https://github.com/karafka/waterdrop
|
167
|
+
licenses:
|
168
|
+
- MIT
|
169
|
+
metadata: {}
|
170
|
+
post_install_message:
|
171
|
+
rdoc_options: []
|
172
|
+
require_paths:
|
173
|
+
- lib
|
174
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: 2.5.0
|
179
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - ">="
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '0'
|
184
|
+
requirements: []
|
185
|
+
rubygems_version: 3.1.4
|
186
|
+
signing_key:
|
187
|
+
specification_version: 4
|
188
|
+
summary: Kafka messaging made easy!
|
189
|
+
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|