waterdrop 2.8.6 → 2.8.8.rc1
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 +4 -4
- data/.github/workflows/ci.yml +23 -5
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +20 -7
- data/bin/verify_kafka_warnings +1 -1
- data/lib/waterdrop/config.rb +4 -1
- data/lib/waterdrop/connection_pool.rb +233 -0
- data/lib/waterdrop/instrumentation/class_monitor.rb +18 -0
- data/lib/waterdrop/instrumentation/class_notifications.rb +22 -0
- data/lib/waterdrop/instrumentation/notifications.rb +1 -1
- data/lib/waterdrop/producer/class_monitor.rb +17 -0
- data/lib/waterdrop/producer.rb +29 -1
- data/lib/waterdrop/version.rb +1 -1
- data/lib/waterdrop.rb +23 -10
- data/waterdrop.gemspec +0 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51626a5ebbcd31ccb011d37675d29da824a0066993cf1a5e0b6117bc49c03c3e
|
4
|
+
data.tar.gz: 9d3755db2b6daf1fd54bed8a526de70237d60ddda4660a1abeab778a5b92183d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9060a4f68526fb4d3522fd58f69eb7a11c8ff58fcb3bc2a7d140715693bf4f4d4342bb2f79a8d7b75b7b4ad3178a3fa1d5732cdf1add8395b4f93d4abf4daee6
|
7
|
+
data.tar.gz: 236a114d76f18fd84a9802583dd32eb4494298d5ec0e9a11677430e474b71639561a98dbf50766998ea994fdb26f136bdc5ee0e1c91ec0553b7e2d81bb76e3e7
|
data/.github/workflows/ci.yml
CHANGED
@@ -6,9 +6,7 @@ concurrency:
|
|
6
6
|
|
7
7
|
on:
|
8
8
|
pull_request:
|
9
|
-
branches: [
|
10
|
-
push:
|
11
|
-
branches: [ main, master ]
|
9
|
+
branches: [ master ]
|
12
10
|
schedule:
|
13
11
|
- cron: '0 1 * * *'
|
14
12
|
|
@@ -30,7 +28,6 @@ jobs:
|
|
30
28
|
- '3.4'
|
31
29
|
- '3.3'
|
32
30
|
- '3.2'
|
33
|
-
- '3.1'
|
34
31
|
force_ruby_platform:
|
35
32
|
- true
|
36
33
|
- false
|
@@ -48,7 +45,7 @@ jobs:
|
|
48
45
|
- name: Remove platform-specific ffi entries for Ruby previews
|
49
46
|
if: contains(matrix.ruby, '3.5')
|
50
47
|
run: |
|
51
|
-
|
48
|
+
sed -i '/^\s*ffi (.*-.*)$/d' Gemfile.lock
|
52
49
|
|
53
50
|
- name: Set up Ruby
|
54
51
|
uses: ruby/setup-ruby@2a7b30092b0caf9c046252510f9273b4875f3db9 # v1.254.0
|
@@ -56,6 +53,7 @@ jobs:
|
|
56
53
|
ruby-version: ${{matrix.ruby}}
|
57
54
|
bundler-cache: true
|
58
55
|
bundler: 'latest'
|
56
|
+
self-hosted: false
|
59
57
|
|
60
58
|
- name: Run Kafka with Docker Compose
|
61
59
|
run: |
|
@@ -91,6 +89,7 @@ jobs:
|
|
91
89
|
|
92
90
|
diffend:
|
93
91
|
timeout-minutes: 5
|
92
|
+
|
94
93
|
runs-on: ubuntu-latest
|
95
94
|
strategy:
|
96
95
|
fail-fast: false
|
@@ -102,6 +101,8 @@ jobs:
|
|
102
101
|
uses: ruby/setup-ruby@2a7b30092b0caf9c046252510f9273b4875f3db9 # v1.254.0
|
103
102
|
with:
|
104
103
|
ruby-version: 3.4
|
104
|
+
self-hosted: false
|
105
|
+
|
105
106
|
- name: Install latest bundler
|
106
107
|
run: gem install bundler --no-document
|
107
108
|
- name: Install Diffend plugin
|
@@ -132,3 +133,20 @@ jobs:
|
|
132
133
|
fi
|
133
134
|
- name: Run Coditsu
|
134
135
|
run: ./coditsu_script.sh
|
136
|
+
|
137
|
+
ci-success:
|
138
|
+
name: CI Success
|
139
|
+
runs-on: ubuntu-latest
|
140
|
+
if: always()
|
141
|
+
needs:
|
142
|
+
- diffend
|
143
|
+
- coditsu
|
144
|
+
- specs
|
145
|
+
steps:
|
146
|
+
- name: Check all jobs passed
|
147
|
+
if: |
|
148
|
+
contains(needs.*.result, 'failure') ||
|
149
|
+
contains(needs.*.result, 'cancelled') ||
|
150
|
+
contains(needs.*.result, 'skipped')
|
151
|
+
run: exit 1
|
152
|
+
- run: echo "All CI checks passed!"
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# WaterDrop changelog
|
2
2
|
|
3
|
+
## 2.8.8 (Unreleased)
|
4
|
+
- [Feature] Add `WaterDrop::ConnectionPool` for efficient connection pooling using the proven `connection_pool` gem.
|
5
|
+
- [Feature] Add `WaterDrop.instrumentation` class-level instrumentation for producer lifecycle events. This allows external libraries to subscribe to `producer.created` and `producer.configured` events without needing producer instance references, enabling middleware injection and configuration by libraries like Datadog tracing.
|
6
|
+
- [Change] Remove Ruby `3.1` specs according to the EOL schedule.
|
7
|
+
|
8
|
+
## 2.8.7 (2025-09-02)
|
9
|
+
- [Enhancement] Disable Nagle algorithm by default (improves latency / aligned with librdkafka)
|
10
|
+
- [Change] Normalize how libs and dependencies are required (no functional change for the end user)
|
11
|
+
|
3
12
|
## 2.8.6 (2025-08-18)
|
4
13
|
- [Feature] Add `idle_disconnect_timeout` config option to automatically disconnect idle producers after a configurable timeout period.
|
5
14
|
- [Feature] Add support for [async](https://github.com/socketry/async) gems ecosystem with proper fiber yielding during blocking operations.
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
waterdrop (2.8.
|
4
|
+
waterdrop (2.8.8.rc1)
|
5
5
|
karafka-core (>= 2.4.9, < 3.0.0)
|
6
6
|
karafka-rdkafka (>= 0.20.0)
|
7
7
|
zeitwerk (~> 2.3)
|
@@ -10,6 +10,7 @@ GEM
|
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
12
|
byebug (12.0.0)
|
13
|
+
connection_pool (2.5.4)
|
13
14
|
diff-lcs (1.6.2)
|
14
15
|
docile (1.4.1)
|
15
16
|
ffi (1.17.2)
|
@@ -23,26 +24,37 @@ GEM
|
|
23
24
|
ffi (1.17.2-x86_64-darwin)
|
24
25
|
ffi (1.17.2-x86_64-linux-gnu)
|
25
26
|
ffi (1.17.2-x86_64-linux-musl)
|
26
|
-
|
27
|
-
|
27
|
+
json (2.13.2)
|
28
|
+
karafka-core (2.5.6)
|
29
|
+
karafka-rdkafka (>= 0.20.0)
|
28
30
|
logger (>= 1.6.0)
|
29
|
-
karafka-rdkafka (0.21.0
|
31
|
+
karafka-rdkafka (0.21.0)
|
32
|
+
ffi (~> 1.15)
|
33
|
+
json (> 2.0)
|
34
|
+
logger
|
35
|
+
mini_portile2 (~> 2.6)
|
36
|
+
rake (> 12)
|
37
|
+
karafka-rdkafka (0.21.0-aarch64-linux-gnu)
|
30
38
|
ffi (~> 1.15)
|
39
|
+
json (> 2.0)
|
31
40
|
logger
|
32
41
|
mini_portile2 (~> 2.6)
|
33
42
|
rake (> 12)
|
34
|
-
karafka-rdkafka (0.21.0
|
43
|
+
karafka-rdkafka (0.21.0-arm64-darwin)
|
35
44
|
ffi (~> 1.15)
|
45
|
+
json (> 2.0)
|
36
46
|
logger
|
37
47
|
mini_portile2 (~> 2.6)
|
38
48
|
rake (> 12)
|
39
|
-
karafka-rdkafka (0.21.0
|
49
|
+
karafka-rdkafka (0.21.0-x86_64-linux-gnu)
|
40
50
|
ffi (~> 1.15)
|
51
|
+
json (> 2.0)
|
41
52
|
logger
|
42
53
|
mini_portile2 (~> 2.6)
|
43
54
|
rake (> 12)
|
44
|
-
karafka-rdkafka (0.21.0
|
55
|
+
karafka-rdkafka (0.21.0-x86_64-linux-musl)
|
45
56
|
ffi (~> 1.15)
|
57
|
+
json (> 2.0)
|
46
58
|
logger
|
47
59
|
mini_portile2 (~> 2.6)
|
48
60
|
rake (> 12)
|
@@ -87,6 +99,7 @@ PLATFORMS
|
|
87
99
|
|
88
100
|
DEPENDENCIES
|
89
101
|
byebug
|
102
|
+
connection_pool
|
90
103
|
ostruct
|
91
104
|
rspec
|
92
105
|
simplecov
|
data/bin/verify_kafka_warnings
CHANGED
data/lib/waterdrop/config.rb
CHANGED
@@ -17,7 +17,10 @@ module WaterDrop
|
|
17
17
|
# sync delivery
|
18
18
|
'message.timeout.ms': 50_000,
|
19
19
|
# Must be more or equal to `message.timeout.ms` defaults
|
20
|
-
'transaction.timeout.ms': 55_000
|
20
|
+
'transaction.timeout.ms': 55_000,
|
21
|
+
# Lowers latency. Default in newer librdkafka but we want to make sure it is shipped to
|
22
|
+
# users despite what librdkafka they run on
|
23
|
+
'socket.nagle.disable': true
|
21
24
|
}.freeze
|
22
25
|
|
23
26
|
private_constant :KAFKA_DEFAULTS
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# WaterDrop library
|
4
|
+
module WaterDrop
|
5
|
+
# Connection pool wrapper for WaterDrop producers using the proven connection_pool gem.
|
6
|
+
#
|
7
|
+
# This provides a clean WaterDrop-specific API while leveraging the battle-tested,
|
8
|
+
# connection_pool gem underneath. The wrapper hides the direct usage of the connection_pool
|
9
|
+
# gem and provides WaterDrop-specific configuration.
|
10
|
+
#
|
11
|
+
# @example Basic usage
|
12
|
+
# pool = WaterDrop::ConnectionPool.new(size: 10) do |config|
|
13
|
+
# config.kafka = { 'bootstrap.servers': 'localhost:9092' }
|
14
|
+
# config.deliver = true
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# pool.with do |producer|
|
18
|
+
# producer.produce_sync(topic: 'events', payload: 'data')
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# @example Transactional producers with unique IDs
|
22
|
+
# pool = WaterDrop::ConnectionPool.new(size: 5) do |config, index|
|
23
|
+
# config.kafka = {
|
24
|
+
# 'bootstrap.servers': 'localhost:9092',
|
25
|
+
# 'transactional.id': "my-app-#{index}"
|
26
|
+
# }
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example Global connection pool
|
30
|
+
# WaterDrop::ConnectionPool.setup(size: 20) do |config|
|
31
|
+
# config.kafka = { 'bootstrap.servers': ENV['KAFKA_BROKERS'] }
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# WaterDrop::ConnectionPool.with do |producer|
|
35
|
+
# producer.produce_async(topic: 'events', payload: 'data')
|
36
|
+
# end
|
37
|
+
class ConnectionPool
|
38
|
+
# Delegate key methods to underlying connection pool
|
39
|
+
extend Forwardable
|
40
|
+
|
41
|
+
def_delegators :@pool, :with, :size, :available
|
42
|
+
|
43
|
+
class << self
|
44
|
+
# Global connection pool instance
|
45
|
+
attr_accessor :default_pool
|
46
|
+
|
47
|
+
# Sets up a global connection pool
|
48
|
+
#
|
49
|
+
# @param size [Integer] Pool size (default: 5)
|
50
|
+
# @param timeout [Numeric] Connection timeout in seconds (default: 5)
|
51
|
+
# @param producer_config [Proc] Block to configure each producer in the pool
|
52
|
+
# @yield [config, index] Block to configure each producer in the pool, receives config and
|
53
|
+
# pool index
|
54
|
+
# @return [ConnectionPool] The configured global pool
|
55
|
+
#
|
56
|
+
# @example Basic setup
|
57
|
+
# WaterDrop::ConnectionPool.setup(size: 15) do |config|
|
58
|
+
# config.kafka = { 'bootstrap.servers': ENV['KAFKA_BROKERS'] }
|
59
|
+
# config.deliver = true
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# @example Transactional setup with unique IDs
|
63
|
+
# WaterDrop::ConnectionPool.setup(size: 5) do |config, index|
|
64
|
+
# config.kafka = {
|
65
|
+
# 'bootstrap.servers': ENV['KAFKA_BROKERS'],
|
66
|
+
# 'transactional.id': "my-app-#{index}"
|
67
|
+
# }
|
68
|
+
# end
|
69
|
+
def setup(size: 5, timeout: 5, &producer_config)
|
70
|
+
ensure_connection_pool_gem!
|
71
|
+
|
72
|
+
@default_pool = new(size: size, timeout: timeout, &producer_config)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Executes a block with a producer from the global pool
|
76
|
+
#
|
77
|
+
# @param block [Proc] Block to execute with a producer
|
78
|
+
# @yield [producer] Producer from the global pool
|
79
|
+
# @return [Object] Result of the block
|
80
|
+
# @raise [RuntimeError] If no global pool is configured
|
81
|
+
#
|
82
|
+
# @example
|
83
|
+
# WaterDrop::ConnectionPool.with do |producer|
|
84
|
+
# producer.produce_sync(topic: 'events', payload: 'data')
|
85
|
+
# end
|
86
|
+
def with(&block)
|
87
|
+
raise 'No global connection pool configured. Call setup first.' unless @default_pool
|
88
|
+
|
89
|
+
@default_pool.with(&block)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Get statistics about the global pool
|
93
|
+
#
|
94
|
+
# @return [Hash, nil] Pool statistics or nil if no global pool
|
95
|
+
def stats
|
96
|
+
return nil unless @default_pool
|
97
|
+
|
98
|
+
{
|
99
|
+
size: @default_pool.size,
|
100
|
+
available: @default_pool.available
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
# Shutdown the global connection pool
|
105
|
+
def shutdown
|
106
|
+
return unless @default_pool
|
107
|
+
|
108
|
+
@default_pool.shutdown
|
109
|
+
@default_pool = nil
|
110
|
+
end
|
111
|
+
|
112
|
+
# Reload the global connection pool
|
113
|
+
def reload
|
114
|
+
@default_pool&.reload
|
115
|
+
end
|
116
|
+
|
117
|
+
# Check if the global connection pool is active (configured)
|
118
|
+
#
|
119
|
+
# @return [Boolean] true if global pool is configured, false otherwise
|
120
|
+
def active?
|
121
|
+
!@default_pool.nil?
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
# Ensures the connection_pool gem is available (class method)
|
127
|
+
# Only requires it when actually needed (lazy loading)
|
128
|
+
def ensure_connection_pool_gem!
|
129
|
+
return if defined?(::ConnectionPool)
|
130
|
+
|
131
|
+
require 'connection_pool'
|
132
|
+
rescue LoadError
|
133
|
+
raise LoadError, <<~ERROR
|
134
|
+
WaterDrop::ConnectionPool requires the 'connection_pool' gem.
|
135
|
+
|
136
|
+
Add this to your Gemfile:
|
137
|
+
gem 'connection_pool'
|
138
|
+
|
139
|
+
Then run:
|
140
|
+
bundle install
|
141
|
+
ERROR
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Creates a new WaterDrop connection pool
|
146
|
+
#
|
147
|
+
# @param size [Integer] Pool size (default: 5)
|
148
|
+
# @param timeout [Numeric] Connection timeout in seconds (default: 5)
|
149
|
+
# @param producer_config [Proc] Block to configure each producer in the pool
|
150
|
+
# @yield [config, index] Block to configure each producer in the pool, receives config and
|
151
|
+
# pool index
|
152
|
+
def initialize(size: 5, timeout: 5, &producer_config)
|
153
|
+
self.class.send(:ensure_connection_pool_gem!)
|
154
|
+
|
155
|
+
@producer_config = producer_config
|
156
|
+
@pool_index = 0
|
157
|
+
@pool_mutex = Mutex.new
|
158
|
+
|
159
|
+
@pool = ::ConnectionPool.new(size: size, timeout: timeout) do
|
160
|
+
producer_index = @pool_mutex.synchronize { @pool_index += 1 }
|
161
|
+
|
162
|
+
WaterDrop::Producer.new do |config|
|
163
|
+
if @producer_config.arity == 2
|
164
|
+
@producer_config.call(config, producer_index)
|
165
|
+
else
|
166
|
+
@producer_config.call(config)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Get pool statistics
|
173
|
+
#
|
174
|
+
# @return [Hash] Pool statistics
|
175
|
+
def stats
|
176
|
+
{
|
177
|
+
size: @pool.size,
|
178
|
+
available: @pool.available
|
179
|
+
}
|
180
|
+
end
|
181
|
+
|
182
|
+
# Shutdown the connection pool
|
183
|
+
def shutdown
|
184
|
+
@pool.shutdown do |producer|
|
185
|
+
producer.close! if producer&.status&.active?
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Reload all connections in the pool
|
190
|
+
# Useful for configuration changes or error recovery
|
191
|
+
def reload
|
192
|
+
@pool.reload do |producer|
|
193
|
+
producer.close! if producer&.status&.active?
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Returns the underlying connection_pool instance
|
198
|
+
# This allows access to advanced connection_pool features if needed
|
199
|
+
#
|
200
|
+
# @return [::ConnectionPool] The underlying connection pool
|
201
|
+
attr_reader :pool
|
202
|
+
end
|
203
|
+
|
204
|
+
# Convenience methods on the WaterDrop module for global pool access
|
205
|
+
class << self
|
206
|
+
# Execute a block with a producer from the global connection pool
|
207
|
+
# Only available when connection pool is configured
|
208
|
+
#
|
209
|
+
# @param block [Proc] Block to execute with a producer
|
210
|
+
# @yield [producer] Producer from the global pool
|
211
|
+
# @return [Object] Result of the block
|
212
|
+
#
|
213
|
+
# @example
|
214
|
+
# WaterDrop.with do |producer|
|
215
|
+
# producer.produce_sync(topic: 'events', payload: 'data')
|
216
|
+
# end
|
217
|
+
def with(&block)
|
218
|
+
ConnectionPool.with(&block)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Access the global connection pool
|
222
|
+
#
|
223
|
+
# @return [WaterDrop::ConnectionPool] The global pool
|
224
|
+
#
|
225
|
+
# @example
|
226
|
+
# WaterDrop.pool.with do |producer|
|
227
|
+
# producer.produce_async(topic: 'events', payload: 'data')
|
228
|
+
# end
|
229
|
+
def pool
|
230
|
+
ConnectionPool.default_pool
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WaterDrop
|
4
|
+
module Instrumentation
|
5
|
+
# WaterDrop class-level instrumentation monitor for global events
|
6
|
+
# This monitor only supports class-level lifecycle events, not per-producer events
|
7
|
+
class ClassMonitor < ::Karafka::Core::Monitoring::Monitor
|
8
|
+
# @param notifications_bus [Object] class-level notifications bus
|
9
|
+
# @param namespace [String, nil] namespace for events or nil if no namespace
|
10
|
+
def initialize(
|
11
|
+
notifications_bus = WaterDrop::Instrumentation::ClassNotifications.new,
|
12
|
+
namespace = nil
|
13
|
+
)
|
14
|
+
super(notifications_bus, namespace)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WaterDrop
|
4
|
+
module Instrumentation
|
5
|
+
# Class-level notifications for WaterDrop global instrumentation
|
6
|
+
# This only supports events that occur at the class/module level, not per-producer instance
|
7
|
+
class ClassNotifications < ::Karafka::Core::Monitoring::Notifications
|
8
|
+
# List of events that are available at the class level via WaterDrop.instrumentation
|
9
|
+
# These are lifecycle events for producer creation and configuration
|
10
|
+
EVENTS = %w[
|
11
|
+
producer.created
|
12
|
+
producer.configured
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
# @return [WaterDrop::Instrumentation::ClassNotifications] class-level notification instance
|
16
|
+
def initialize
|
17
|
+
super
|
18
|
+
EVENTS.each { |event| register_event(event) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -4,7 +4,7 @@ module WaterDrop
|
|
4
4
|
module Instrumentation
|
5
5
|
# Instrumented is used to hookup external monitoring services to monitor how WaterDrop works
|
6
6
|
class Notifications < ::Karafka::Core::Monitoring::Notifications
|
7
|
-
# List of events that we support
|
7
|
+
# List of events that we support at the instance level (per-producer instrumentation)
|
8
8
|
# @note The non-error once support timestamp benchmarking
|
9
9
|
EVENTS = %w[
|
10
10
|
producer.connected
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WaterDrop
|
4
|
+
class Producer
|
5
|
+
# Module that provides class-level instrumentation capabilities to producers
|
6
|
+
# This allows producers to emit lifecycle events that can be subscribed to at the global level
|
7
|
+
module ClassMonitor
|
8
|
+
private
|
9
|
+
|
10
|
+
# @return [WaterDrop::Instrumentation::ClassMonitor] global class-level monitor for
|
11
|
+
# instrumentation events
|
12
|
+
def class_monitor
|
13
|
+
WaterDrop.instrumentation
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/waterdrop/producer.rb
CHANGED
@@ -8,6 +8,7 @@ module WaterDrop
|
|
8
8
|
include Async
|
9
9
|
include Buffer
|
10
10
|
include Transactions
|
11
|
+
include ClassMonitor
|
11
12
|
include ::Karafka::Core::Helpers::Time
|
12
13
|
include ::Karafka::Core::Taggable
|
13
14
|
|
@@ -60,6 +61,13 @@ module WaterDrop
|
|
60
61
|
@status = Status.new
|
61
62
|
@messages = []
|
62
63
|
|
64
|
+
# Instrument producer creation for global listeners
|
65
|
+
class_monitor.instrument(
|
66
|
+
'producer.created',
|
67
|
+
producer: self,
|
68
|
+
producer_id: @id
|
69
|
+
)
|
70
|
+
|
63
71
|
return unless block
|
64
72
|
|
65
73
|
setup(&block)
|
@@ -80,7 +88,19 @@ module WaterDrop
|
|
80
88
|
@contract = Contracts::Message.new(max_payload_size: @config.max_payload_size)
|
81
89
|
@default_variant = Variant.new(self, default: true)
|
82
90
|
|
83
|
-
|
91
|
+
if @config.idle_disconnect_timeout.zero?
|
92
|
+
@status.configured!
|
93
|
+
|
94
|
+
# Instrument producer configuration for global listeners
|
95
|
+
class_monitor.instrument(
|
96
|
+
'producer.configured',
|
97
|
+
producer: self,
|
98
|
+
producer_id: @id,
|
99
|
+
config: @config
|
100
|
+
)
|
101
|
+
|
102
|
+
return
|
103
|
+
end
|
84
104
|
|
85
105
|
# Setup idle disconnect listener if configured so we preserve tcp connections on rarely
|
86
106
|
# used producers
|
@@ -92,6 +112,14 @@ module WaterDrop
|
|
92
112
|
@monitor.subscribe(disconnector)
|
93
113
|
|
94
114
|
@status.configured!
|
115
|
+
|
116
|
+
# Instrument producer configuration for global listeners
|
117
|
+
class_monitor.instrument(
|
118
|
+
'producer.configured',
|
119
|
+
producer: self,
|
120
|
+
producer_id: @id,
|
121
|
+
config: @config
|
122
|
+
)
|
95
123
|
end
|
96
124
|
|
97
125
|
# @return [Rdkafka::Producer] raw rdkafka producer
|
data/lib/waterdrop/version.rb
CHANGED
data/lib/waterdrop.rb
CHANGED
@@ -1,16 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# External components
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
karafka-core
|
12
|
-
pathname
|
13
|
-
].each { |lib| require lib }
|
4
|
+
require 'delegate'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'json'
|
7
|
+
require 'zeitwerk'
|
8
|
+
require 'securerandom'
|
9
|
+
require 'karafka-core'
|
10
|
+
require 'pathname'
|
14
11
|
|
15
12
|
# WaterDrop library
|
16
13
|
module WaterDrop
|
@@ -19,6 +16,22 @@ module WaterDrop
|
|
19
16
|
def gem_root
|
20
17
|
Pathname.new(File.expand_path('..', __dir__))
|
21
18
|
end
|
19
|
+
|
20
|
+
# @return [WaterDrop::Instrumentation::ClassMonitor] global instrumentation monitor for
|
21
|
+
# class-level event subscriptions. This allows external libraries to subscribe to WaterDrop
|
22
|
+
# lifecycle events without needing producer instance references.
|
23
|
+
#
|
24
|
+
# @note Only supports class-level events (producer.created, producer.configured), not
|
25
|
+
# instance events
|
26
|
+
#
|
27
|
+
# @example Subscribe to producer creation events
|
28
|
+
# WaterDrop.instrumentation.subscribe('producer.created') do |event|
|
29
|
+
# producer = event[:producer]
|
30
|
+
# # Configure producer or add middleware
|
31
|
+
# end
|
32
|
+
def instrumentation
|
33
|
+
@instrumentation ||= Instrumentation::ClassMonitor.new
|
34
|
+
end
|
22
35
|
end
|
23
36
|
end
|
24
37
|
|
data/waterdrop.gemspec
CHANGED
@@ -27,7 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.require_paths = %w[lib]
|
28
28
|
|
29
29
|
spec.metadata = {
|
30
|
-
'funding_uri' => 'https://karafka.io/#become-pro',
|
31
30
|
'homepage_uri' => 'https://karafka.io',
|
32
31
|
'changelog_uri' => 'https://karafka.io/docs/Changelog-WaterDrop',
|
33
32
|
'bug_tracker_uri' => 'https://github.com/karafka/waterdrop/issues',
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: waterdrop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.8.
|
4
|
+
version: 2.8.8.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maciej Mensfeld
|
@@ -94,6 +94,7 @@ files:
|
|
94
94
|
- lib/waterdrop/clients/dummy.rb
|
95
95
|
- lib/waterdrop/clients/rdkafka.rb
|
96
96
|
- lib/waterdrop/config.rb
|
97
|
+
- lib/waterdrop/connection_pool.rb
|
97
98
|
- lib/waterdrop/contracts.rb
|
98
99
|
- lib/waterdrop/contracts/config.rb
|
99
100
|
- lib/waterdrop/contracts/message.rb
|
@@ -105,6 +106,8 @@ files:
|
|
105
106
|
- lib/waterdrop/instrumentation/callbacks/error.rb
|
106
107
|
- lib/waterdrop/instrumentation/callbacks/oauthbearer_token_refresh.rb
|
107
108
|
- lib/waterdrop/instrumentation/callbacks/statistics.rb
|
109
|
+
- lib/waterdrop/instrumentation/class_monitor.rb
|
110
|
+
- lib/waterdrop/instrumentation/class_notifications.rb
|
108
111
|
- lib/waterdrop/instrumentation/idle_disconnector_listener.rb
|
109
112
|
- lib/waterdrop/instrumentation/logger_listener.rb
|
110
113
|
- lib/waterdrop/instrumentation/monitor.rb
|
@@ -116,6 +119,7 @@ files:
|
|
116
119
|
- lib/waterdrop/producer/async.rb
|
117
120
|
- lib/waterdrop/producer/buffer.rb
|
118
121
|
- lib/waterdrop/producer/builder.rb
|
122
|
+
- lib/waterdrop/producer/class_monitor.rb
|
119
123
|
- lib/waterdrop/producer/status.rb
|
120
124
|
- lib/waterdrop/producer/sync.rb
|
121
125
|
- lib/waterdrop/producer/transactions.rb
|
@@ -129,7 +133,6 @@ licenses:
|
|
129
133
|
- LGPL-3.0-only
|
130
134
|
- Commercial
|
131
135
|
metadata:
|
132
|
-
funding_uri: https://karafka.io/#become-pro
|
133
136
|
homepage_uri: https://karafka.io
|
134
137
|
changelog_uri: https://karafka.io/docs/Changelog-WaterDrop
|
135
138
|
bug_tracker_uri: https://github.com/karafka/waterdrop/issues
|