karafka 1.4.13 → 2.0.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.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -3
  3. data/.github/workflows/ci.yml +85 -30
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +268 -7
  6. data/CONTRIBUTING.md +10 -19
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +44 -87
  9. data/LICENSE +17 -0
  10. data/LICENSE-COMM +89 -0
  11. data/LICENSE-LGPL +165 -0
  12. data/README.md +44 -48
  13. data/bin/benchmarks +85 -0
  14. data/bin/create_token +22 -0
  15. data/bin/integrations +237 -0
  16. data/bin/karafka +4 -0
  17. data/bin/scenario +29 -0
  18. data/bin/stress_many +13 -0
  19. data/bin/stress_one +13 -0
  20. data/bin/wait_for_kafka +20 -0
  21. data/certs/karafka-pro.pem +11 -0
  22. data/config/errors.yml +55 -40
  23. data/docker-compose.yml +39 -3
  24. data/karafka.gemspec +11 -17
  25. data/lib/active_job/karafka.rb +21 -0
  26. data/lib/active_job/queue_adapters/karafka_adapter.rb +26 -0
  27. data/lib/karafka/active_job/consumer.rb +26 -0
  28. data/lib/karafka/active_job/dispatcher.rb +38 -0
  29. data/lib/karafka/active_job/job_extensions.rb +34 -0
  30. data/lib/karafka/active_job/job_options_contract.rb +21 -0
  31. data/lib/karafka/active_job/routing/extensions.rb +31 -0
  32. data/lib/karafka/app.rb +15 -20
  33. data/lib/karafka/base_consumer.rb +181 -31
  34. data/lib/karafka/cli/base.rb +4 -4
  35. data/lib/karafka/cli/info.rb +43 -9
  36. data/lib/karafka/cli/install.rb +19 -10
  37. data/lib/karafka/cli/server.rb +17 -42
  38. data/lib/karafka/cli.rb +4 -11
  39. data/lib/karafka/connection/client.rb +385 -90
  40. data/lib/karafka/connection/listener.rb +246 -38
  41. data/lib/karafka/connection/listeners_batch.rb +24 -0
  42. data/lib/karafka/connection/messages_buffer.rb +84 -0
  43. data/lib/karafka/connection/pauses_manager.rb +46 -0
  44. data/lib/karafka/connection/raw_messages_buffer.rb +101 -0
  45. data/lib/karafka/connection/rebalance_manager.rb +78 -0
  46. data/lib/karafka/contracts/base.rb +17 -0
  47. data/lib/karafka/contracts/config.rb +88 -11
  48. data/lib/karafka/contracts/consumer_group.rb +21 -189
  49. data/lib/karafka/contracts/consumer_group_topic.rb +34 -11
  50. data/lib/karafka/contracts/server_cli_options.rb +19 -18
  51. data/lib/karafka/contracts.rb +1 -1
  52. data/lib/karafka/env.rb +46 -0
  53. data/lib/karafka/errors.rb +21 -21
  54. data/lib/karafka/helpers/async.rb +33 -0
  55. data/lib/karafka/helpers/colorize.rb +20 -0
  56. data/lib/karafka/helpers/multi_delegator.rb +2 -2
  57. data/lib/karafka/instrumentation/callbacks/error.rb +40 -0
  58. data/lib/karafka/instrumentation/callbacks/statistics.rb +41 -0
  59. data/lib/karafka/instrumentation/logger_listener.rb +164 -0
  60. data/lib/karafka/instrumentation/monitor.rb +13 -61
  61. data/lib/karafka/instrumentation/notifications.rb +52 -0
  62. data/lib/karafka/instrumentation/proctitle_listener.rb +3 -3
  63. data/lib/karafka/instrumentation/vendors/datadog/dashboard.json +1 -0
  64. data/lib/karafka/instrumentation/vendors/datadog/listener.rb +232 -0
  65. data/lib/karafka/instrumentation.rb +21 -0
  66. data/lib/karafka/licenser.rb +75 -0
  67. data/lib/karafka/messages/batch_metadata.rb +45 -0
  68. data/lib/karafka/messages/builders/batch_metadata.rb +40 -0
  69. data/lib/karafka/messages/builders/message.rb +39 -0
  70. data/lib/karafka/messages/builders/messages.rb +32 -0
  71. data/lib/karafka/{params/params.rb → messages/message.rb} +7 -12
  72. data/lib/karafka/messages/messages.rb +64 -0
  73. data/lib/karafka/{params → messages}/metadata.rb +4 -6
  74. data/lib/karafka/messages/seek.rb +9 -0
  75. data/lib/karafka/patches/rdkafka/consumer.rb +22 -0
  76. data/lib/karafka/pro/active_job/consumer.rb +46 -0
  77. data/lib/karafka/pro/active_job/dispatcher.rb +61 -0
  78. data/lib/karafka/pro/active_job/job_options_contract.rb +32 -0
  79. data/lib/karafka/pro/base_consumer.rb +82 -0
  80. data/lib/karafka/pro/contracts/base.rb +21 -0
  81. data/lib/karafka/pro/contracts/consumer_group.rb +34 -0
  82. data/lib/karafka/pro/contracts/consumer_group_topic.rb +33 -0
  83. data/lib/karafka/pro/loader.rb +76 -0
  84. data/lib/karafka/pro/performance_tracker.rb +80 -0
  85. data/lib/karafka/pro/processing/coordinator.rb +72 -0
  86. data/lib/karafka/pro/processing/jobs/consume_non_blocking.rb +37 -0
  87. data/lib/karafka/pro/processing/jobs_builder.rb +32 -0
  88. data/lib/karafka/pro/processing/partitioner.rb +60 -0
  89. data/lib/karafka/pro/processing/scheduler.rb +56 -0
  90. data/lib/karafka/pro/routing/builder_extensions.rb +30 -0
  91. data/lib/karafka/pro/routing/topic_extensions.rb +38 -0
  92. data/lib/karafka/pro.rb +13 -0
  93. data/lib/karafka/process.rb +1 -0
  94. data/lib/karafka/processing/coordinator.rb +88 -0
  95. data/lib/karafka/processing/coordinators_buffer.rb +54 -0
  96. data/lib/karafka/processing/executor.rb +118 -0
  97. data/lib/karafka/processing/executors_buffer.rb +88 -0
  98. data/lib/karafka/processing/jobs/base.rb +51 -0
  99. data/lib/karafka/processing/jobs/consume.rb +42 -0
  100. data/lib/karafka/processing/jobs/revoked.rb +22 -0
  101. data/lib/karafka/processing/jobs/shutdown.rb +23 -0
  102. data/lib/karafka/processing/jobs_builder.rb +29 -0
  103. data/lib/karafka/processing/jobs_queue.rb +144 -0
  104. data/lib/karafka/processing/partitioner.rb +22 -0
  105. data/lib/karafka/processing/result.rb +29 -0
  106. data/lib/karafka/processing/scheduler.rb +22 -0
  107. data/lib/karafka/processing/worker.rb +88 -0
  108. data/lib/karafka/processing/workers_batch.rb +27 -0
  109. data/lib/karafka/railtie.rb +113 -0
  110. data/lib/karafka/routing/builder.rb +15 -24
  111. data/lib/karafka/routing/consumer_group.rb +11 -19
  112. data/lib/karafka/routing/consumer_mapper.rb +1 -2
  113. data/lib/karafka/routing/router.rb +1 -1
  114. data/lib/karafka/routing/subscription_group.rb +53 -0
  115. data/lib/karafka/routing/subscription_groups_builder.rb +53 -0
  116. data/lib/karafka/routing/topic.rb +61 -24
  117. data/lib/karafka/routing/topics.rb +38 -0
  118. data/lib/karafka/runner.rb +51 -0
  119. data/lib/karafka/serialization/json/deserializer.rb +6 -15
  120. data/lib/karafka/server.rb +67 -26
  121. data/lib/karafka/setup/config.rb +147 -175
  122. data/lib/karafka/status.rb +14 -5
  123. data/lib/karafka/templates/example_consumer.rb.erb +16 -0
  124. data/lib/karafka/templates/karafka.rb.erb +15 -51
  125. data/lib/karafka/time_trackers/base.rb +19 -0
  126. data/lib/karafka/time_trackers/pause.rb +92 -0
  127. data/lib/karafka/time_trackers/poll.rb +65 -0
  128. data/lib/karafka/version.rb +1 -1
  129. data/lib/karafka.rb +38 -17
  130. data.tar.gz.sig +0 -0
  131. metadata +118 -120
  132. metadata.gz.sig +0 -0
  133. data/MIT-LICENCE +0 -18
  134. data/lib/karafka/assignment_strategies/round_robin.rb +0 -13
  135. data/lib/karafka/attributes_map.rb +0 -63
  136. data/lib/karafka/backends/inline.rb +0 -16
  137. data/lib/karafka/base_responder.rb +0 -226
  138. data/lib/karafka/cli/flow.rb +0 -48
  139. data/lib/karafka/cli/missingno.rb +0 -19
  140. data/lib/karafka/code_reloader.rb +0 -67
  141. data/lib/karafka/connection/api_adapter.rb +0 -158
  142. data/lib/karafka/connection/batch_delegator.rb +0 -55
  143. data/lib/karafka/connection/builder.rb +0 -23
  144. data/lib/karafka/connection/message_delegator.rb +0 -36
  145. data/lib/karafka/consumers/batch_metadata.rb +0 -10
  146. data/lib/karafka/consumers/callbacks.rb +0 -71
  147. data/lib/karafka/consumers/includer.rb +0 -64
  148. data/lib/karafka/consumers/responders.rb +0 -24
  149. data/lib/karafka/consumers/single_params.rb +0 -15
  150. data/lib/karafka/contracts/responder_usage.rb +0 -54
  151. data/lib/karafka/fetcher.rb +0 -42
  152. data/lib/karafka/helpers/class_matcher.rb +0 -88
  153. data/lib/karafka/helpers/config_retriever.rb +0 -46
  154. data/lib/karafka/helpers/inflector.rb +0 -26
  155. data/lib/karafka/instrumentation/stdout_listener.rb +0 -140
  156. data/lib/karafka/params/batch_metadata.rb +0 -26
  157. data/lib/karafka/params/builders/batch_metadata.rb +0 -30
  158. data/lib/karafka/params/builders/params.rb +0 -38
  159. data/lib/karafka/params/builders/params_batch.rb +0 -25
  160. data/lib/karafka/params/params_batch.rb +0 -60
  161. data/lib/karafka/patches/ruby_kafka.rb +0 -47
  162. data/lib/karafka/persistence/client.rb +0 -29
  163. data/lib/karafka/persistence/consumers.rb +0 -45
  164. data/lib/karafka/persistence/topics.rb +0 -48
  165. data/lib/karafka/responders/builder.rb +0 -36
  166. data/lib/karafka/responders/topic.rb +0 -55
  167. data/lib/karafka/routing/topic_mapper.rb +0 -53
  168. data/lib/karafka/serialization/json/serializer.rb +0 -31
  169. data/lib/karafka/setup/configurators/water_drop.rb +0 -36
  170. data/lib/karafka/templates/application_responder.rb.erb +0 -11
@@ -1,19 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  <% if rails? -%>
4
- ENV['RAILS_ENV'] ||= 'development'
5
- ENV['KARAFKA_ENV'] = ENV['RAILS_ENV']
6
4
  require ::File.expand_path('../config/environment', __FILE__)
7
- Rails.application.eager_load!
8
-
9
- # This lines will make Karafka print to stdout like puma or unicorn
10
- if Rails.env.development?
11
- Rails.logger.extend(
12
- ActiveSupport::Logger.broadcast(
13
- ActiveSupport::Logger.new($stdout)
14
- )
15
- )
16
- end
17
5
  <% else -%>
18
6
  # This file is auto-generated during the install process.
19
7
  # If by any chance you've wanted a setup for Rails app, either run the `karafka:install`
@@ -31,9 +19,7 @@ APP_LOADER.enable_reloading
31
19
  %w[
32
20
  lib
33
21
  app/consumers
34
- app/responders
35
- app/workers
36
- ].each(&APP_LOADER.method(:push_dir))
22
+ ].each { |dir| APP_LOADER.push_dir(dir) }
37
23
 
38
24
  APP_LOADER.setup
39
25
  APP_LOADER.eager_load
@@ -41,10 +27,12 @@ APP_LOADER.eager_load
41
27
 
42
28
  class KarafkaApp < Karafka::App
43
29
  setup do |config|
44
- config.kafka.seed_brokers = %w[kafka://127.0.0.1:9092]
30
+ config.kafka = { 'bootstrap.servers': '127.0.0.1:9092' }
45
31
  config.client_id = 'example_app'
46
32
  <% if rails? -%>
47
- config.logger = Rails.logger
33
+ # Recreate consumers with each batch. This will allow Rails code reload to work in the
34
+ # development mode. Otherwise Karafka process would not be aware of code changes
35
+ config.consumer_persistence = !Rails.env.development?
48
36
  <% end -%>
49
37
  end
50
38
 
@@ -52,41 +40,17 @@ class KarafkaApp < Karafka::App
52
40
  # interested in logging events for certain environments. Since instrumentation
53
41
  # notifications add extra boilerplate, if you want to achieve max performance,
54
42
  # listen to only what you really need for given environment.
55
- Karafka.monitor.subscribe(WaterDrop::Instrumentation::StdoutListener.new)
56
- Karafka.monitor.subscribe(Karafka::Instrumentation::StdoutListener.new)
43
+ Karafka.monitor.subscribe(Karafka::Instrumentation::LoggerListener.new)
57
44
  # Karafka.monitor.subscribe(Karafka::Instrumentation::ProctitleListener.new)
58
45
 
59
- # Uncomment that in order to achieve code reload in development mode
60
- # Be aware, that this might have some side-effects. Please refer to the wiki
61
- # for more details on benefits and downsides of the code reload in the
62
- # development mode
63
- #
64
- # Karafka.monitor.subscribe(
65
- # Karafka::CodeReloader.new(
66
- # <%= rails? ? '*Rails.application.reloaders' : 'APP_LOADER' %>
67
- # )
68
- # )
69
-
70
- consumer_groups.draw do
71
- # topic :example do
72
- # consumer ExampleConsumer
73
- # end
74
-
75
- # consumer_group :bigger_group do
76
- # topic :test do
77
- # consumer TestConsumer
78
- # end
79
- #
80
- # topic :test2 do
81
- # consumer Test2Consumer
82
- # end
83
- # end
46
+ routes.draw do
47
+ <% if rails? -%>
48
+ # Uncomment this if you use Karafka with ActiveJob
49
+ # You ned to define the topic per each queue name you use
50
+ # active_job_topic :default
51
+ <% end -%>
52
+ topic :example do
53
+ consumer ExampleConsumer
54
+ end
84
55
  end
85
56
  end
86
-
87
- Karafka.monitor.subscribe('app.initialized') do
88
- # Put here all the things you want to do after the Karafka framework
89
- # initialization
90
- end
91
-
92
- KarafkaApp.boot!
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ # Time trackers module.
5
+ #
6
+ # Time trackers are used to track time in context of having a time poll (amount of time
7
+ # available for processing) or a pausing engine (pause for a time period).
8
+ module TimeTrackers
9
+ # Base class for all the time-trackers.
10
+ class Base
11
+ private
12
+
13
+ # @return [Float] current time in milliseconds
14
+ def now
15
+ ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) * 1000
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module TimeTrackers
5
+ # Handles Kafka topic partition pausing and resuming with exponential back-offs.
6
+ class Pause < Base
7
+ attr_reader :count
8
+
9
+ # @param timeout [Integer] how long should we wait when anything went wrong (in ms)
10
+ # @param max_timeout [Integer, nil] if exponential is on, what is the max value we can reach
11
+ # exponentially on which we will stay
12
+ # @param exponential_backoff [Boolean] should we wait exponentially or with the same
13
+ # timeout value
14
+ # @return [Karafka::TimeTrackers::Pause]
15
+ # @example
16
+ # pause = Karafka::TimeTrackers::Pause.new(timeout: 1000)
17
+ # pause.expired? #=> true
18
+ # pause.paused? #=> false
19
+ # pause.pause
20
+ # sleep(1.1)
21
+ # pause.paused? #=> true
22
+ # pause.expired? #=> true
23
+ # pause.count #=> 1
24
+ # pause.pause
25
+ # pause.count #=> 1
26
+ # pause.paused? #=> true
27
+ # pause.expired? #=> false
28
+ # pause.resume
29
+ # pause.count #=> 2
30
+ # pause.paused? #=> false
31
+ # pause.reset
32
+ # pause.count #=> 0
33
+ def initialize(timeout:, max_timeout:, exponential_backoff:)
34
+ @started_at = nil
35
+ @count = 0
36
+ @timeout = timeout
37
+ @max_timeout = max_timeout
38
+ @exponential_backoff = exponential_backoff
39
+ super()
40
+ end
41
+
42
+ # Pauses the processing from now till the end of the interval (backoff or non-backoff)
43
+ # and records the count.
44
+ # @param timeout [Integer] timeout value in milliseconds that overwrites the default timeout
45
+ # @note Providing this value can be useful when we explicitly want to pause for a certain
46
+ # period of time, outside of any regular pausing logic
47
+ def pause(timeout = backoff_interval)
48
+ @started_at = now
49
+ @ends_at = @started_at + timeout
50
+ @count += 1
51
+ end
52
+
53
+ # Marks the pause as resumed.
54
+ def resume
55
+ @started_at = nil
56
+ @ends_at = nil
57
+ end
58
+
59
+ # Expires the pause, so it can be considered expired
60
+ def expire
61
+ @ends_at = nil
62
+ end
63
+
64
+ # @return [Boolean] are we paused from processing
65
+ def paused?
66
+ !@started_at.nil?
67
+ end
68
+
69
+ # @return [Boolean] did the pause expire
70
+ def expired?
71
+ @ends_at ? now >= @ends_at : true
72
+ end
73
+
74
+ # Resets the pause counter.
75
+ def reset
76
+ @count = 0
77
+ end
78
+
79
+ private
80
+
81
+ # Computers the exponential backoff
82
+ # @return [Integer] backoff in milliseconds
83
+ def backoff_interval
84
+ backoff_factor = @exponential_backoff ? 2**@count : 1
85
+
86
+ timeout = backoff_factor * @timeout
87
+
88
+ @max_timeout && timeout > @max_timeout ? @max_timeout : timeout
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module TimeTrackers
5
+ # Object used to keep track of time we've used running certain operations.
6
+ #
7
+ # @example Keep track of sleeping and stop after 3 seconds of 0.1 sleep intervals
8
+ # time_poll = Poll.new(3000)
9
+ # time_poll.start
10
+ #
11
+ # until time_poll.exceeded?
12
+ # time_poll.start
13
+ # puts "I have #{time_poll.remaining.to_i}ms remaining to sleep..."
14
+ # sleep(0.1)
15
+ # time_poll.checkpoint
16
+ # end
17
+ class Poll < Base
18
+ attr_reader :remaining, :attempts
19
+
20
+ # @param total_time [Integer] amount of milliseconds before we exceed the given time limit
21
+ # @return [TimeTracker] time poll instance
22
+ def initialize(total_time)
23
+ @remaining = total_time
24
+ @attempts = 0
25
+ super()
26
+ end
27
+
28
+ # @return [Boolean] did we exceed the time limit
29
+ def exceeded?
30
+ @remaining <= 0
31
+ end
32
+
33
+ # Starts time tracking.
34
+ def start
35
+ @attempts += 1
36
+ @started_at = now
37
+ end
38
+
39
+ # Stops time tracking of a given piece of code and updates the remaining time.
40
+ def checkpoint
41
+ @remaining -= (now - @started_at)
42
+ end
43
+
44
+ # @return [Boolean] If anything went wrong, can we retry after a backoff period or not
45
+ # (do we have enough time)
46
+ def retryable?
47
+ remaining > backoff_interval
48
+ end
49
+
50
+ # Sleeps for amount of time matching attempt, so we sleep more with each attempt in case of
51
+ # a retry.
52
+ def backoff
53
+ # Sleep requires seconds not ms
54
+ sleep(backoff_interval / 1_000.0)
55
+ end
56
+
57
+ private
58
+
59
+ # @return [Integer] milliseconds of the backoff time
60
+ def backoff_interval
61
+ 100 * attempts
62
+ end
63
+ end
64
+ end
65
+ end
@@ -3,5 +3,5 @@
3
3
  # Main module namespace
4
4
  module Karafka
5
5
  # Current Karafka version
6
- VERSION = '1.4.13'
6
+ VERSION = '2.0.0'
7
7
  end
data/lib/karafka.rb CHANGED
@@ -1,34 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  %w[
4
+ karafka-core
4
5
  delegate
5
6
  English
7
+ rdkafka
6
8
  waterdrop
7
- kafka
8
- envlogic
9
9
  json
10
10
  thor
11
11
  forwardable
12
12
  fileutils
13
- dry-configurable
14
- dry-validation
15
- dry/events/publisher
16
- dry/inflector
17
- dry/monitor/notifications
18
- dry/core/constants
13
+ openssl
14
+ base64
15
+ date
19
16
  zeitwerk
20
17
  ].each(&method(:require))
21
18
 
22
- # Karafka library
19
+ # Karafka framework main namespace
23
20
  module Karafka
24
- extend Envlogic
25
-
26
21
  class << self
22
+ # @return [Karafka::Env] env instance that allows us to check environment
23
+ def env
24
+ @env ||= Env.new
25
+ end
26
+
27
+ # @param environment [String, Symbol] new environment that we want to set
28
+ # @return [Karafka::Env] env instance
29
+ # @example Assign new environment to Karafka::App
30
+ # Karafka::App.env = :production
31
+ def env=(environment)
32
+ env.replace(environment.to_s)
33
+ end
34
+
27
35
  # @return [Logger] logger that we want to use. Will use ::Karafka::Logger by default
28
36
  def logger
29
37
  @logger ||= App.config.logger
30
38
  end
31
39
 
40
+ # @return [WaterDrop::Producer] waterdrop messages producer
41
+ def producer
42
+ @producer ||= App.config.producer
43
+ end
44
+
32
45
  # @return [::Karafka::Monitor] monitor that we want to use
33
46
  def monitor
34
47
  @monitor ||= App.config.monitor
@@ -49,6 +62,11 @@ module Karafka
49
62
  Pathname.new(File.expand_path('karafka', __dir__))
50
63
  end
51
64
 
65
+ # @return [Boolean] true if there is a valid pro token present
66
+ def pro?
67
+ App.config.license.token != false
68
+ end
69
+
52
70
  # @return [String] path to a default file that contains booting procedure etc
53
71
  # @note By default it is a file called 'karafka.rb' but it can be specified as you wish if you
54
72
  # have Karafka that is merged into a Sinatra/Rails app and karafka.rb is taken.
@@ -64,9 +82,12 @@ module Karafka
64
82
  end
65
83
  end
66
84
 
67
- Zeitwerk::Loader
68
- .for_gem
69
- .tap(&:setup)
70
- .tap(&:eager_load)
71
-
72
- Kafka::Consumer.prepend(Karafka::Patches::RubyKafka)
85
+ loader = Zeitwerk::Loader.for_gem
86
+ # Do not load Rails extensions by default, this will be handled by Railtie if they are needed
87
+ loader.ignore(Karafka.gem_root.join('lib/active_job'))
88
+ # Do not load pro components, this will be handled by license manager
89
+ loader.ignore(Karafka.gem_root.join('lib/karafka/pro'))
90
+ # Do not load vendors instrumentation components. Those need to be required manually if needed
91
+ loader.ignore(Karafka.gem_root.join('lib/karafka/instrumentation/vendors'))
92
+ loader.setup
93
+ loader.eager_load
data.tar.gz.sig CHANGED
Binary file