waterdrop 2.0.7 → 2.6.14

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/.github/workflows/ci.yml +39 -13
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +212 -0
  7. data/Gemfile +0 -2
  8. data/Gemfile.lock +45 -75
  9. data/README.md +22 -275
  10. data/certs/cert_chain.pem +26 -0
  11. data/config/locales/errors.yml +39 -0
  12. data/docker-compose.yml +21 -12
  13. data/lib/waterdrop/clients/buffered.rb +95 -0
  14. data/lib/waterdrop/clients/dummy.rb +69 -0
  15. data/lib/waterdrop/clients/rdkafka.rb +34 -0
  16. data/lib/{water_drop → waterdrop}/config.rb +39 -16
  17. data/lib/waterdrop/contracts/config.rb +43 -0
  18. data/lib/waterdrop/contracts/message.rb +64 -0
  19. data/lib/waterdrop/contracts/transactional_offset.rb +21 -0
  20. data/lib/{water_drop → waterdrop}/errors.rb +23 -7
  21. data/lib/waterdrop/helpers/counter.rb +27 -0
  22. data/lib/waterdrop/instrumentation/callbacks/delivery.rb +106 -0
  23. data/lib/{water_drop → waterdrop}/instrumentation/callbacks/error.rb +6 -2
  24. data/lib/{water_drop → waterdrop}/instrumentation/callbacks/statistics.rb +1 -1
  25. data/lib/{water_drop/instrumentation/stdout_listener.rb → waterdrop/instrumentation/logger_listener.rb} +91 -21
  26. data/lib/waterdrop/instrumentation/monitor.rb +20 -0
  27. data/lib/{water_drop/instrumentation/monitor.rb → waterdrop/instrumentation/notifications.rb} +15 -14
  28. data/lib/waterdrop/instrumentation/vendors/datadog/dashboard.json +1 -0
  29. data/lib/waterdrop/instrumentation/vendors/datadog/metrics_listener.rb +210 -0
  30. data/lib/waterdrop/middleware.rb +50 -0
  31. data/lib/{water_drop → waterdrop}/producer/async.rb +40 -4
  32. data/lib/{water_drop → waterdrop}/producer/buffer.rb +13 -31
  33. data/lib/{water_drop → waterdrop}/producer/builder.rb +6 -11
  34. data/lib/{water_drop → waterdrop}/producer/sync.rb +44 -15
  35. data/lib/waterdrop/producer/transactions.rb +219 -0
  36. data/lib/waterdrop/producer.rb +324 -0
  37. data/lib/{water_drop → waterdrop}/version.rb +1 -1
  38. data/lib/waterdrop.rb +27 -2
  39. data/renovate.json +6 -0
  40. data/waterdrop.gemspec +14 -11
  41. data.tar.gz.sig +0 -0
  42. metadata +73 -111
  43. metadata.gz.sig +0 -0
  44. data/certs/mensfeld.pem +0 -25
  45. data/config/errors.yml +0 -6
  46. data/lib/water_drop/contracts/config.rb +0 -26
  47. data/lib/water_drop/contracts/message.rb +0 -42
  48. data/lib/water_drop/instrumentation/callbacks/delivery.rb +0 -30
  49. data/lib/water_drop/instrumentation/callbacks/statistics_decorator.rb +0 -77
  50. data/lib/water_drop/instrumentation/callbacks_manager.rb +0 -39
  51. data/lib/water_drop/instrumentation.rb +0 -20
  52. data/lib/water_drop/patches/rdkafka/bindings.rb +0 -42
  53. data/lib/water_drop/patches/rdkafka/producer.rb +0 -20
  54. data/lib/water_drop/producer/dummy_client.rb +0 -32
  55. data/lib/water_drop/producer.rb +0 -162
  56. data/lib/water_drop.rb +0 -36
  57. /data/lib/{water_drop → waterdrop}/contracts.rb +0 -0
  58. /data/lib/{water_drop → waterdrop}/producer/status.rb +0 -0
@@ -1,162 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module WaterDrop
4
- # Main WaterDrop messages producer
5
- class Producer
6
- include Sync
7
- include Async
8
- include Buffer
9
-
10
- # @return [String] uuid of the current producer
11
- attr_reader :id
12
- # @return [Status] producer status object
13
- attr_reader :status
14
- # @return [Concurrent::Array] internal messages buffer
15
- attr_reader :messages
16
- # @return [Object] monitor we want to use
17
- attr_reader :monitor
18
- # @return [Object] dry-configurable config object
19
- attr_reader :config
20
-
21
- # Creates a not-yet-configured instance of the producer
22
- # @param block [Proc] configuration block
23
- # @return [Producer] producer instance
24
- def initialize(&block)
25
- @buffer_mutex = Mutex.new
26
- @connecting_mutex = Mutex.new
27
- @closing_mutex = Mutex.new
28
-
29
- @status = Status.new
30
- @messages = Concurrent::Array.new
31
-
32
- return unless block
33
-
34
- setup(&block)
35
- end
36
-
37
- # Sets up the whole configuration and initializes all that is needed
38
- # @param block [Block] configuration block
39
- def setup(&block)
40
- raise Errors::ProducerAlreadyConfiguredError, id unless @status.initial?
41
-
42
- @config = Config
43
- .new
44
- .setup(&block)
45
- .config
46
-
47
- @id = @config.id
48
- @monitor = @config.monitor
49
- @contract = Contracts::Message.new(max_payload_size: @config.max_payload_size)
50
- @status.configured!
51
- end
52
-
53
- # @return [Rdkafka::Producer] raw rdkafka producer
54
- # @note Client is lazy initialized, keeping in mind also the fact of a potential fork that
55
- # can happen any time.
56
- # @note It is not recommended to fork a producer that is already in use so in case of
57
- # bootstrapping a cluster, it's much better to fork configured but not used producers
58
- def client
59
- return @client if @client && @pid == Process.pid
60
-
61
- # Don't allow to obtain a client reference for a producer that was not configured
62
- raise Errors::ProducerNotConfiguredError, id if @status.initial?
63
-
64
- @connecting_mutex.synchronize do
65
- return @client if @client && @pid == Process.pid
66
-
67
- # We should raise an error when trying to use a producer from a fork, that is already
68
- # connected to Kafka. We allow forking producers only before they are used
69
- raise Errors::ProducerUsedInParentProcess, Process.pid if @status.connected?
70
-
71
- # We undefine all the finalizers, in case it was a fork, so the finalizers from the parent
72
- # process don't leak
73
- ObjectSpace.undefine_finalizer(id)
74
- # Finalizer tracking is needed for handling shutdowns gracefully.
75
- # I don't expect everyone to remember about closing all the producers all the time, thus
76
- # this approach is better. Although it is still worth keeping in mind, that this will
77
- # block GC from removing a no longer used producer unless closed properly but at least
78
- # won't crash the VM upon closing the process
79
- ObjectSpace.define_finalizer(id, proc { close })
80
-
81
- @pid = Process.pid
82
- @client = Builder.new.call(self, @config)
83
-
84
- # Register statistics runner for this particular type of callbacks
85
- ::WaterDrop::Instrumentation.statistics_callbacks.add(
86
- @id,
87
- Instrumentation::Callbacks::Statistics.new(@id, @client.name, @config.monitor)
88
- )
89
-
90
- # Register error tracking callback
91
- ::WaterDrop::Instrumentation.error_callbacks.add(
92
- @id,
93
- Instrumentation::Callbacks::Error.new(@id, @client.name, @config.monitor)
94
- )
95
-
96
- @status.connected!
97
- end
98
-
99
- @client
100
- end
101
-
102
- # Flushes the buffers in a sync way and closes the producer
103
- def close
104
- @closing_mutex.synchronize do
105
- return unless @status.active?
106
-
107
- @monitor.instrument(
108
- 'producer.closed',
109
- producer_id: id
110
- ) do
111
- @status.closing!
112
-
113
- # No need for auto-gc if everything got closed by us
114
- # This should be used only in case a producer was not closed properly and forgotten
115
- ObjectSpace.undefine_finalizer(id)
116
-
117
- # Flush has its own buffer mutex but even if it is blocked, flushing can still happen
118
- # as we close the client after the flushing (even if blocked by the mutex)
119
- flush(true)
120
-
121
- # We should not close the client in several threads the same time
122
- # It is safe to run it several times but not exactly the same moment
123
- # We also mark it as closed only if it was connected, if not, it would trigger a new
124
- # connection that anyhow would be immediately closed
125
- client.close if @client
126
-
127
- # Remove callbacks runners that were registered
128
- ::WaterDrop::Instrumentation.statistics_callbacks.delete(@id)
129
- ::WaterDrop::Instrumentation.error_callbacks.delete(@id)
130
-
131
- @status.closed!
132
- end
133
- end
134
- end
135
-
136
- # Ensures that we don't run any operations when the producer is not configured or when it
137
- # was already closed
138
- def ensure_active!
139
- return if @status.active?
140
-
141
- raise Errors::ProducerNotConfiguredError, id if @status.initial?
142
- raise Errors::ProducerClosedError, id if @status.closing? || @status.closed?
143
-
144
- # This should never happen
145
- raise Errors::StatusInvalidError, [id, @status.to_s]
146
- end
147
-
148
- # Ensures that the message we want to send out to Kafka is actually valid and that it can be
149
- # sent there
150
- # @param message [Hash] message we want to send
151
- # @raise [Karafka::Errors::MessageInvalidError]
152
- def validate_message!(message)
153
- result = @contract.call(message)
154
- return if result.success?
155
-
156
- raise Errors::MessageInvalidError, [
157
- result.errors.to_h,
158
- message
159
- ]
160
- end
161
- end
162
- end
data/lib/water_drop.rb DELETED
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # External components
4
- # delegate should be removed because we don't need it, we just add it because of ruby-kafka
5
- %w[
6
- concurrent/array
7
- dry-configurable
8
- dry/monitor/notifications
9
- dry-validation
10
- rdkafka
11
- json
12
- zeitwerk
13
- securerandom
14
- ].each { |lib| require lib }
15
-
16
- # WaterDrop library
17
- module WaterDrop
18
- class << self
19
- # @return [String] root path of this gem
20
- def gem_root
21
- Pathname.new(File.expand_path('..', __dir__))
22
- end
23
- end
24
- end
25
-
26
- Zeitwerk::Loader
27
- .for_gem
28
- .tap { |loader| loader.ignore("#{__dir__}/waterdrop.rb") }
29
- .tap(&:setup)
30
- .tap(&:eager_load)
31
-
32
- # Rdkafka uses a single global callback for things. We bypass that by injecting a manager for
33
- # each callback type. Callback manager allows us to register more than one callback
34
- # @note Those managers are also used by Karafka for consumer related statistics
35
- Rdkafka::Config.statistics_callback = WaterDrop::Instrumentation.statistics_callbacks
36
- Rdkafka::Config.error_callback = WaterDrop::Instrumentation.error_callbacks
File without changes
File without changes