waterdrop 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # WaterDrop library
4
+ module WaterDrop
5
+ # Current WaterDrop version
6
+ VERSION = '1.4.0'
7
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is used as a compatibility step
4
+ require 'water_drop'
File without changes
@@ -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: []
Binary file