karafka 2.2.13 → 2.3.0.alpha1
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
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ci.yml +38 -12
- data/.ruby-version +1 -1
- data/CHANGELOG.md +161 -125
- data/Gemfile.lock +12 -12
- data/README.md +0 -2
- data/SECURITY.md +23 -0
- data/config/locales/errors.yml +7 -1
- data/config/locales/pro_errors.yml +22 -0
- data/docker-compose.yml +3 -1
- data/karafka.gemspec +2 -2
- data/lib/karafka/admin/acl.rb +287 -0
- data/lib/karafka/admin.rb +118 -16
- data/lib/karafka/app.rb +12 -3
- data/lib/karafka/base_consumer.rb +32 -31
- data/lib/karafka/cli/base.rb +1 -1
- data/lib/karafka/connection/client.rb +94 -84
- data/lib/karafka/connection/conductor.rb +28 -0
- data/lib/karafka/connection/listener.rb +165 -46
- data/lib/karafka/connection/listeners_batch.rb +5 -11
- data/lib/karafka/connection/manager.rb +72 -0
- data/lib/karafka/connection/messages_buffer.rb +12 -0
- data/lib/karafka/connection/proxy.rb +17 -0
- data/lib/karafka/connection/status.rb +75 -0
- data/lib/karafka/contracts/config.rb +14 -10
- data/lib/karafka/contracts/consumer_group.rb +9 -1
- data/lib/karafka/contracts/topic.rb +3 -1
- data/lib/karafka/errors.rb +13 -0
- data/lib/karafka/instrumentation/assignments_tracker.rb +96 -0
- data/lib/karafka/instrumentation/callbacks/rebalance.rb +10 -7
- data/lib/karafka/instrumentation/logger_listener.rb +3 -9
- data/lib/karafka/instrumentation/notifications.rb +19 -9
- data/lib/karafka/instrumentation/vendors/appsignal/metrics_listener.rb +31 -28
- data/lib/karafka/instrumentation/vendors/datadog/logger_listener.rb +22 -3
- data/lib/karafka/instrumentation/vendors/datadog/metrics_listener.rb +15 -12
- data/lib/karafka/instrumentation/vendors/kubernetes/liveness_listener.rb +39 -36
- data/lib/karafka/pro/base_consumer.rb +47 -0
- data/lib/karafka/pro/connection/manager.rb +300 -0
- data/lib/karafka/pro/connection/multiplexing/listener.rb +40 -0
- data/lib/karafka/pro/instrumentation/performance_tracker.rb +85 -0
- data/lib/karafka/pro/iterator/tpl_builder.rb +1 -1
- data/lib/karafka/pro/iterator.rb +1 -6
- data/lib/karafka/pro/loader.rb +16 -2
- data/lib/karafka/pro/processing/coordinator.rb +2 -1
- data/lib/karafka/pro/processing/executor.rb +37 -0
- data/lib/karafka/pro/processing/expansions_selector.rb +32 -0
- data/lib/karafka/pro/processing/jobs/periodic.rb +41 -0
- data/lib/karafka/pro/processing/jobs/periodic_non_blocking.rb +32 -0
- data/lib/karafka/pro/processing/jobs_builder.rb +14 -3
- data/lib/karafka/pro/processing/offset_metadata/consumer.rb +44 -0
- data/lib/karafka/pro/processing/offset_metadata/fetcher.rb +131 -0
- data/lib/karafka/pro/processing/offset_metadata/listener.rb +46 -0
- data/lib/karafka/pro/processing/schedulers/base.rb +143 -0
- data/lib/karafka/pro/processing/schedulers/default.rb +107 -0
- data/lib/karafka/pro/processing/strategies/aj/lrj_mom_vp.rb +1 -1
- data/lib/karafka/pro/processing/strategies/default.rb +136 -3
- data/lib/karafka/pro/processing/strategies/dlq/default.rb +35 -0
- data/lib/karafka/pro/processing/strategies/lrj/default.rb +1 -1
- data/lib/karafka/pro/processing/strategies/lrj/mom.rb +1 -1
- data/lib/karafka/pro/processing/strategies/vp/default.rb +60 -26
- data/lib/karafka/pro/processing/virtual_offset_manager.rb +41 -11
- data/lib/karafka/pro/routing/features/long_running_job/topic.rb +2 -0
- data/lib/karafka/pro/routing/features/multiplexing/config.rb +38 -0
- data/lib/karafka/pro/routing/features/multiplexing/contracts/topic.rb +114 -0
- data/lib/karafka/pro/routing/features/multiplexing/patches/contracts/consumer_group.rb +42 -0
- data/lib/karafka/pro/routing/features/multiplexing/proxy.rb +38 -0
- data/lib/karafka/pro/routing/features/multiplexing/subscription_group.rb +42 -0
- data/lib/karafka/pro/routing/features/multiplexing/subscription_groups_builder.rb +40 -0
- data/lib/karafka/pro/routing/features/multiplexing.rb +59 -0
- data/lib/karafka/pro/routing/features/non_blocking_job/topic.rb +32 -0
- data/lib/karafka/pro/routing/features/non_blocking_job.rb +37 -0
- data/lib/karafka/pro/routing/features/offset_metadata/config.rb +33 -0
- data/lib/karafka/pro/routing/features/offset_metadata/contracts/topic.rb +42 -0
- data/lib/karafka/pro/routing/features/offset_metadata/topic.rb +65 -0
- data/lib/karafka/pro/routing/features/offset_metadata.rb +40 -0
- data/lib/karafka/pro/routing/features/patterns/contracts/consumer_group.rb +4 -0
- data/lib/karafka/pro/routing/features/patterns/detector.rb +18 -10
- data/lib/karafka/pro/routing/features/periodic_job/config.rb +37 -0
- data/lib/karafka/pro/routing/features/periodic_job/contracts/topic.rb +44 -0
- data/lib/karafka/pro/routing/features/periodic_job/topic.rb +94 -0
- data/lib/karafka/pro/routing/features/periodic_job.rb +27 -0
- data/lib/karafka/pro/routing/features/virtual_partitions/config.rb +1 -0
- data/lib/karafka/pro/routing/features/virtual_partitions/contracts/topic.rb +1 -0
- data/lib/karafka/pro/routing/features/virtual_partitions/topic.rb +7 -2
- data/lib/karafka/process.rb +5 -3
- data/lib/karafka/processing/coordinator.rb +5 -1
- data/lib/karafka/processing/executor.rb +43 -13
- data/lib/karafka/processing/executors_buffer.rb +22 -7
- data/lib/karafka/processing/jobs/base.rb +19 -2
- data/lib/karafka/processing/jobs/consume.rb +3 -3
- data/lib/karafka/processing/jobs/idle.rb +5 -0
- data/lib/karafka/processing/jobs/revoked.rb +5 -0
- data/lib/karafka/processing/jobs/shutdown.rb +5 -0
- data/lib/karafka/processing/jobs_queue.rb +19 -8
- data/lib/karafka/processing/schedulers/default.rb +42 -0
- data/lib/karafka/processing/strategies/base.rb +13 -4
- data/lib/karafka/processing/strategies/default.rb +23 -7
- data/lib/karafka/processing/strategies/dlq.rb +36 -0
- data/lib/karafka/processing/worker.rb +4 -1
- data/lib/karafka/routing/builder.rb +12 -2
- data/lib/karafka/routing/consumer_group.rb +5 -5
- data/lib/karafka/routing/features/base.rb +44 -8
- data/lib/karafka/routing/features/dead_letter_queue/config.rb +6 -1
- data/lib/karafka/routing/features/dead_letter_queue/contracts/topic.rb +1 -0
- data/lib/karafka/routing/features/dead_letter_queue/topic.rb +9 -2
- data/lib/karafka/routing/proxy.rb +4 -3
- data/lib/karafka/routing/subscription_group.rb +2 -2
- data/lib/karafka/routing/subscription_groups_builder.rb +11 -2
- data/lib/karafka/routing/topic.rb +8 -10
- data/lib/karafka/routing/topics.rb +1 -1
- data/lib/karafka/runner.rb +13 -3
- data/lib/karafka/server.rb +5 -9
- data/lib/karafka/setup/config.rb +21 -1
- data/lib/karafka/status.rb +23 -14
- data/lib/karafka/templates/karafka.rb.erb +7 -0
- data/lib/karafka/time_trackers/partition_usage.rb +56 -0
- data/lib/karafka/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +47 -13
- metadata.gz.sig +0 -0
- data/lib/karafka/connection/consumer_group_coordinator.rb +0 -48
- data/lib/karafka/pro/performance_tracker.rb +0 -84
- data/lib/karafka/pro/processing/scheduler.rb +0 -74
- data/lib/karafka/processing/scheduler.rb +0 -38
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
class NonBlockingJob < Base
|
|
19
|
+
# Non-Blocking Jobs topic API extensions
|
|
20
|
+
module Topic
|
|
21
|
+
# @param args [Array] anything accepted by the `#long_running_job` API
|
|
22
|
+
def non_blocking_job(*args)
|
|
23
|
+
long_running_job(*args)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
alias non_blocking non_blocking_job
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
# Namespace for Pro routing enhancements
|
|
17
|
+
module Routing
|
|
18
|
+
# Namespace for additional Pro features
|
|
19
|
+
module Features
|
|
20
|
+
# Non Blocking Job is just an alias for LRJ.
|
|
21
|
+
#
|
|
22
|
+
# We however have it as a separate feature because its use-case may vary from LRJ.
|
|
23
|
+
#
|
|
24
|
+
# While LRJ is used mainly for long-running jobs that would take more than max poll
|
|
25
|
+
# interval time, non-blocking can be applied to make sure that we do not wait with polling
|
|
26
|
+
# of different partitions and topics that are subscribed together.
|
|
27
|
+
#
|
|
28
|
+
# This effectively allows for better resources utilization
|
|
29
|
+
#
|
|
30
|
+
# All the underlying code is the same but use-case is different and this should be
|
|
31
|
+
# reflected in the routing, hence this "virtual" feature.
|
|
32
|
+
class NonBlockingJob < Base
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
class OffsetMetadata < Base
|
|
19
|
+
# Config for commit metadata feature
|
|
20
|
+
Config = Struct.new(
|
|
21
|
+
:active,
|
|
22
|
+
:deserializer,
|
|
23
|
+
:cache,
|
|
24
|
+
keyword_init: true
|
|
25
|
+
) do
|
|
26
|
+
alias_method :active?, :active
|
|
27
|
+
alias_method :cache?, :cache
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
class OffsetMetadata < Base
|
|
19
|
+
# Namespace for offset metadata feature contracts
|
|
20
|
+
module Contracts
|
|
21
|
+
# Contract to validate configuration of the expiring feature
|
|
22
|
+
class Topic < Karafka::Contracts::Base
|
|
23
|
+
configure do |config|
|
|
24
|
+
config.error_messages = YAML.safe_load(
|
|
25
|
+
File.read(
|
|
26
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'pro_errors.yml')
|
|
27
|
+
)
|
|
28
|
+
).fetch('en').fetch('validations').fetch('topic')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
nested(:offset_metadata) do
|
|
32
|
+
required(:active) { |val| val == true }
|
|
33
|
+
required(:cache) { |val| [true, false].include?(val) }
|
|
34
|
+
required(:deserializer) { |val| val.respond_to?(:call) }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
# This feature allows for saving and retrieving offset metadata with custom deserialization
|
|
19
|
+
# support. It allows for storing extra data during commits that can be then used to alter
|
|
20
|
+
# the processing flow after a rebalance.
|
|
21
|
+
#
|
|
22
|
+
# @note Because this feature has zero performance impact and makes no queries to Kafka
|
|
23
|
+
# unless requested, it is always enabled.
|
|
24
|
+
class OffsetMetadata < Base
|
|
25
|
+
# Empty string not to create it on each deserialization
|
|
26
|
+
EMPTY_STRING = ''
|
|
27
|
+
|
|
28
|
+
# Default deserializer just ensures we always get a string as without metadata by
|
|
29
|
+
# default it would be nil
|
|
30
|
+
STRING_DESERIALIZER = ->(raw_metadata) { raw_metadata || EMPTY_STRING }.freeze
|
|
31
|
+
|
|
32
|
+
private_constant :STRING_DESERIALIZER, :EMPTY_STRING
|
|
33
|
+
|
|
34
|
+
# Commit Metadata API extensions
|
|
35
|
+
module Topic
|
|
36
|
+
# @param cache [Boolean] should we cache the response until rebalance
|
|
37
|
+
# @param deserializer [#call] deserializer that will get raw data and should return
|
|
38
|
+
# deserialized metadata
|
|
39
|
+
# @return [Config] this feature config
|
|
40
|
+
def offset_metadata(cache: true, deserializer: STRING_DESERIALIZER)
|
|
41
|
+
@offset_metadata ||= Config.new(
|
|
42
|
+
active: true,
|
|
43
|
+
cache: cache,
|
|
44
|
+
deserializer: deserializer
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [true] is offset metadata active (it always is)
|
|
49
|
+
def offset_metadata?
|
|
50
|
+
offset_metadata.active?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [Hash] topic with all its native configuration options plus offset metadata
|
|
54
|
+
# settings
|
|
55
|
+
def to_h
|
|
56
|
+
super.merge(
|
|
57
|
+
offset_metadata: offset_metadata.to_h
|
|
58
|
+
).freeze
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
# Offset Metadata Support with a custom deserializer
|
|
19
|
+
class OffsetMetadata < Base
|
|
20
|
+
class << self
|
|
21
|
+
# If needed installs the needed listener and initializes tracker
|
|
22
|
+
#
|
|
23
|
+
# @param _config [Karafka::Core::Configurable::Node] app config
|
|
24
|
+
def post_setup(_config)
|
|
25
|
+
::Karafka::App.monitor.subscribe('app.running') do
|
|
26
|
+
# Initialize the tracker prior to becoming multi-threaded
|
|
27
|
+
::Karafka::Processing::InlineInsights::Tracker.instance
|
|
28
|
+
|
|
29
|
+
# Subscribe to the statistics reports and collect them
|
|
30
|
+
::Karafka.monitor.subscribe(
|
|
31
|
+
::Karafka::Pro::Processing::OffsetMetadata::Listener.new
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -46,7 +46,11 @@ module Karafka
|
|
|
46
46
|
next unless errors.empty?
|
|
47
47
|
|
|
48
48
|
regexp_strings = data[:patterns].map { |pattern| pattern.fetch(:regexp_string) }
|
|
49
|
+
regexp_names = data[:patterns].map { |pattern| pattern.fetch(:name) }
|
|
49
50
|
|
|
51
|
+
# If all names are the same for the same regexp, it means its a multiplex and
|
|
52
|
+
# we can allow it
|
|
53
|
+
next if regexp_names.uniq.size == 1 && regexp_strings.uniq.size == 1
|
|
50
54
|
next if regexp_strings.empty?
|
|
51
55
|
next if regexp_strings.uniq.size == regexp_strings.size
|
|
52
56
|
|
|
@@ -22,6 +22,12 @@ module Karafka
|
|
|
22
22
|
# @note This is NOT thread-safe and should run in a thread-safe context that warranties
|
|
23
23
|
# that there won't be any race conditions
|
|
24
24
|
class Detector
|
|
25
|
+
# Mutex for making sure that we do not modify same consumer group in runtime at the
|
|
26
|
+
# same time from multiple subscription groups if they operate in a multiplexed mode
|
|
27
|
+
MUTEX = Mutex.new
|
|
28
|
+
|
|
29
|
+
private_constant :MUTEX
|
|
30
|
+
|
|
25
31
|
# Checks if the provided topic matches any of the patterns and when detected, expands
|
|
26
32
|
# the routing with it.
|
|
27
33
|
#
|
|
@@ -29,16 +35,18 @@ module Karafka
|
|
|
29
35
|
# topics.
|
|
30
36
|
# @param new_topic [String] new topic that we have detected
|
|
31
37
|
def expand(sg_topics, new_topic)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
MUTEX.synchronize do
|
|
39
|
+
sg_topics
|
|
40
|
+
.map(&:patterns)
|
|
41
|
+
.select(&:active?)
|
|
42
|
+
.select(&:matcher?)
|
|
43
|
+
.map(&:pattern)
|
|
44
|
+
.then { |pts| pts.empty? ? return : pts }
|
|
45
|
+
.then { |pts| Patterns.new(pts) }
|
|
46
|
+
.find(new_topic)
|
|
47
|
+
.then { |pattern| pattern || return }
|
|
48
|
+
.then { |pattern| install(pattern, new_topic, sg_topics) }
|
|
49
|
+
end
|
|
42
50
|
end
|
|
43
51
|
|
|
44
52
|
private
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
class PeriodicJob < Base
|
|
19
|
+
# Config for periodics topics feature
|
|
20
|
+
Config = Struct.new(
|
|
21
|
+
:active,
|
|
22
|
+
:during_pause,
|
|
23
|
+
:during_retry,
|
|
24
|
+
:interval,
|
|
25
|
+
:materialized,
|
|
26
|
+
keyword_init: true
|
|
27
|
+
) do
|
|
28
|
+
alias_method :active?, :active
|
|
29
|
+
alias_method :during_pause?, :during_pause
|
|
30
|
+
alias_method :during_retry?, :during_retry
|
|
31
|
+
alias_method :materialized?, :materialized
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
class PeriodicJob < Base
|
|
19
|
+
# Namespace for periodics messages contracts
|
|
20
|
+
module Contracts
|
|
21
|
+
# Contract to validate configuration of the periodics feature
|
|
22
|
+
class Topic < Karafka::Contracts::Base
|
|
23
|
+
configure do |config|
|
|
24
|
+
config.error_messages = YAML.safe_load(
|
|
25
|
+
File.read(
|
|
26
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'pro_errors.yml')
|
|
27
|
+
)
|
|
28
|
+
).fetch('en').fetch('validations').fetch('topic')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
nested(:periodic_job) do
|
|
32
|
+
required(:active) { |val| [true, false].include?(val) }
|
|
33
|
+
required(:interval) { |val| val.is_a?(Integer) && val >= 100 }
|
|
34
|
+
required(:during_pause) { |val| [true, false].include?(val) }
|
|
35
|
+
required(:during_retry) { |val| [true, false].include?(val) }
|
|
36
|
+
required(:materialized) { |val| [true, false].include?(val) }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
class PeriodicJob < Base
|
|
19
|
+
# Periodic topic action flows extensions
|
|
20
|
+
module Topic
|
|
21
|
+
# Defines topic as periodic. Periodic topics consumers will invoke `#tick` with each
|
|
22
|
+
# poll where messages were not received.
|
|
23
|
+
# @param active [Boolean] should ticking happen for this topic assignments.
|
|
24
|
+
# @param interval [Integer] minimum interval to run periodic jobs on given topic.
|
|
25
|
+
# @param during_pause [Boolean, nil] Should periodic jobs run when partition is paused.
|
|
26
|
+
# It is set to `nil` by default allowing for detection when this value is not
|
|
27
|
+
# configured but should be built dynamically based on LRJ status.
|
|
28
|
+
# @param during_retry [Boolean, nil] Should we run when there was an error and we are
|
|
29
|
+
# in a retry flow. Please note that for this to work, `during_pause` also needs to be
|
|
30
|
+
# set to true as errors retry happens after pause.
|
|
31
|
+
def periodic_job(
|
|
32
|
+
active = false,
|
|
33
|
+
interval: nil,
|
|
34
|
+
during_pause: nil,
|
|
35
|
+
during_retry: nil
|
|
36
|
+
)
|
|
37
|
+
@periodic_job ||= begin
|
|
38
|
+
# Set to active if any of the values was configured
|
|
39
|
+
active = true unless interval.nil?
|
|
40
|
+
active = true unless during_pause.nil?
|
|
41
|
+
active = true unless during_retry.nil?
|
|
42
|
+
# Default is not to retry during retry flow
|
|
43
|
+
during_retry = false if during_retry.nil?
|
|
44
|
+
|
|
45
|
+
# If no interval, use default
|
|
46
|
+
interval ||= ::Karafka::App.config.internal.tick_interval
|
|
47
|
+
|
|
48
|
+
Config.new(
|
|
49
|
+
active: active,
|
|
50
|
+
interval: interval,
|
|
51
|
+
during_pause: during_pause,
|
|
52
|
+
during_retry: during_retry,
|
|
53
|
+
# This is internal setting for state management, not part of the configuration
|
|
54
|
+
# Do not overwrite.
|
|
55
|
+
# If `during_pause` is explicit, we do not select it based on LRJ setup and we
|
|
56
|
+
# consider if fully ready out of the box
|
|
57
|
+
materialized: !during_pause.nil?
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
return @periodic_job if @periodic_job.materialized?
|
|
62
|
+
return @periodic_job unless @long_running_job
|
|
63
|
+
|
|
64
|
+
# If not configured in any way, we want not to process during pause for LRJ.
|
|
65
|
+
# LRJ pauses by default when processing and during this time we do not want to
|
|
66
|
+
# tick at all. This prevents us from running periodic jobs while LRJ jobs are
|
|
67
|
+
# running. This of course has a side effect of not running when paused for any
|
|
68
|
+
# other reason but it is a compromise in the default settings
|
|
69
|
+
@periodic_job.during_pause = !long_running_job?
|
|
70
|
+
@periodic_job.materialized = true
|
|
71
|
+
|
|
72
|
+
@periodic_job
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
alias periodic periodic_job
|
|
76
|
+
|
|
77
|
+
# @return [Boolean] is periodics active
|
|
78
|
+
def periodic_job?
|
|
79
|
+
periodic_job.active?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @return [Hash] topic with all its native configuration options plus periodics flows
|
|
83
|
+
# settings
|
|
84
|
+
def to_h
|
|
85
|
+
super.merge(
|
|
86
|
+
periodic_job: periodic_job.to_h
|
|
87
|
+
).freeze
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This Karafka component is a Pro component under a commercial license.
|
|
4
|
+
# This Karafka component is NOT licensed under LGPL.
|
|
5
|
+
#
|
|
6
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
|
7
|
+
# repository and their usage requires commercial license agreement.
|
|
8
|
+
#
|
|
9
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
10
|
+
#
|
|
11
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
|
12
|
+
# your code to Maciej Mensfeld.
|
|
13
|
+
|
|
14
|
+
module Karafka
|
|
15
|
+
module Pro
|
|
16
|
+
module Routing
|
|
17
|
+
module Features
|
|
18
|
+
# Feature allowing to run consumer operations even when no data is present on periodic
|
|
19
|
+
# interval.
|
|
20
|
+
# This allows for advanced window-based operations regardless of income of new data and
|
|
21
|
+
# other advanced cases where the consumer is needed even when no data is coming
|
|
22
|
+
class PeriodicJob < Base
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -32,6 +32,7 @@ module Karafka
|
|
|
32
32
|
required(:active) { |val| [true, false].include?(val) }
|
|
33
33
|
required(:partitioner) { |val| val.nil? || val.respond_to?(:call) }
|
|
34
34
|
required(:max_partitions) { |val| val.is_a?(Integer) && val >= 1 }
|
|
35
|
+
required(:offset_metadata_strategy) { |val| %i[exact current].include?(val) }
|
|
35
36
|
end
|
|
36
37
|
|
|
37
38
|
# When virtual partitions are defined, partitioner needs to respond to `#call` and it
|
|
@@ -23,16 +23,21 @@ module Karafka
|
|
|
23
23
|
# create more work than workers. When less, can ensure we have spare resources to
|
|
24
24
|
# process other things in parallel.
|
|
25
25
|
# @param partitioner [nil, #call] nil or callable partitioner
|
|
26
|
+
# @param offset_metadata_strategy [Symbol] how we should match the metadata for the
|
|
27
|
+
# offset. `:exact` will match the offset matching metadata and `:current` will select
|
|
28
|
+
# the most recently reported metadata
|
|
26
29
|
# @return [VirtualPartitions] method that allows to set the virtual partitions details
|
|
27
30
|
# during the routing configuration and then allows to retrieve it
|
|
28
31
|
def virtual_partitions(
|
|
29
32
|
max_partitions: Karafka::App.config.concurrency,
|
|
30
|
-
partitioner: nil
|
|
33
|
+
partitioner: nil,
|
|
34
|
+
offset_metadata_strategy: :current
|
|
31
35
|
)
|
|
32
36
|
@virtual_partitions ||= Config.new(
|
|
33
37
|
active: !partitioner.nil?,
|
|
34
38
|
max_partitions: max_partitions,
|
|
35
|
-
partitioner: partitioner
|
|
39
|
+
partitioner: partitioner,
|
|
40
|
+
offset_metadata_strategy: offset_metadata_strategy
|
|
36
41
|
)
|
|
37
42
|
end
|
|
38
43
|
|
data/lib/karafka/process.rb
CHANGED
|
@@ -25,9 +25,11 @@ module Karafka
|
|
|
25
25
|
# Karafka.logger.info('Log something here')
|
|
26
26
|
# exit
|
|
27
27
|
# end
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
29
|
+
def on_#{signal.to_s.downcase}(&block)
|
|
30
|
+
@callbacks[:#{signal}] << block
|
|
31
|
+
end
|
|
32
|
+
RUBY
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
# Creates an instance of process and creates empty hash for callbacks
|
|
@@ -10,8 +10,12 @@ module Karafka
|
|
|
10
10
|
# listener thread, but we go with thread-safe by default for all not to worry about potential
|
|
11
11
|
# future mistakes.
|
|
12
12
|
class Coordinator
|
|
13
|
+
extend Forwardable
|
|
14
|
+
|
|
13
15
|
attr_reader :pause_tracker, :seek_offset, :topic, :partition
|
|
14
16
|
|
|
17
|
+
def_delegators :@pause_tracker, :attempt, :paused?
|
|
18
|
+
|
|
15
19
|
# @param topic [Karafka::Routing::Topic]
|
|
16
20
|
# @param partition [Integer]
|
|
17
21
|
# @param pause_tracker [Karafka::TimeTrackers::Pause] pause tracker for given topic partition
|
|
@@ -149,7 +153,7 @@ module Karafka
|
|
|
149
153
|
|
|
150
154
|
# @return [Boolean] are we in a pause that was initiated by the user
|
|
151
155
|
def manual_pause?
|
|
152
|
-
|
|
156
|
+
paused? && @manual_pause
|
|
153
157
|
end
|
|
154
158
|
|
|
155
159
|
# Marks seek as manual for coordination purposes
|