karafka 2.1.12 → 2.2.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +41 -0
- data/Gemfile.lock +1 -1
- data/bin/record_rss +50 -0
- data/config/locales/errors.yml +4 -0
- data/config/locales/pro_errors.yml +17 -0
- data/lib/karafka/admin.rb +21 -33
- data/lib/karafka/connection/client.rb +1 -1
- data/lib/karafka/contracts/config.rb +24 -0
- data/lib/karafka/errors.rb +3 -0
- data/lib/karafka/instrumentation/vendors/datadog/logger_listener.rb +5 -2
- data/lib/karafka/messages/builders/message.rb +8 -4
- data/lib/karafka/pro/active_job/consumer.rb +1 -1
- data/lib/karafka/pro/cleaner/errors.rb +27 -0
- data/lib/karafka/pro/cleaner/messages/message.rb +46 -0
- data/lib/karafka/pro/cleaner/messages/messages.rb +42 -0
- data/lib/karafka/pro/cleaner.rb +41 -0
- data/lib/karafka/pro/contracts/base.rb +23 -0
- data/lib/karafka/pro/contracts/server_cli_options.rb +111 -0
- data/lib/karafka/pro/encryption/errors.rb +4 -1
- data/lib/karafka/pro/loader.rb +6 -2
- data/lib/karafka/pro/processing/strategies/dlq/default.rb +6 -0
- data/lib/karafka/pro/routing/features/active_job/builder.rb +45 -0
- data/lib/karafka/pro/routing/features/active_job.rb +26 -0
- data/lib/karafka/pro/routing/features/dead_letter_queue/contracts/topic.rb +53 -0
- data/lib/karafka/pro/routing/features/delaying/contracts/topic.rb +41 -0
- data/lib/karafka/pro/routing/features/expiring/contracts/topic.rb +41 -0
- data/lib/karafka/pro/routing/features/filtering/contracts/topic.rb +44 -0
- data/lib/karafka/pro/routing/features/long_running_job/{contract.rb → contracts/topic.rb} +14 -11
- data/lib/karafka/pro/routing/features/{filtering/contract.rb → patterns/builder.rb} +13 -16
- data/lib/karafka/pro/routing/features/patterns/config.rb +54 -0
- data/lib/karafka/pro/routing/features/patterns/consumer_group.rb +68 -0
- data/lib/karafka/pro/routing/features/patterns/contracts/consumer_group.rb +62 -0
- data/lib/karafka/pro/routing/features/patterns/contracts/pattern.rb +46 -0
- data/lib/karafka/pro/routing/features/patterns/contracts/topic.rb +41 -0
- data/lib/karafka/pro/routing/features/patterns/detector.rb +68 -0
- data/lib/karafka/pro/routing/features/patterns/pattern.rb +81 -0
- data/lib/karafka/pro/routing/features/{delaying/contract.rb → patterns/patterns.rb} +11 -14
- data/lib/karafka/pro/routing/features/patterns/topic.rb +50 -0
- data/lib/karafka/pro/routing/features/patterns/topics.rb +53 -0
- data/lib/karafka/pro/routing/features/patterns.rb +33 -0
- data/lib/karafka/pro/routing/features/pausing/contracts/topic.rb +51 -0
- data/lib/karafka/pro/routing/features/throttling/contracts/topic.rb +44 -0
- data/lib/karafka/pro/routing/features/virtual_partitions/contracts/topic.rb +55 -0
- data/lib/karafka/routing/consumer_group.rb +1 -1
- data/lib/karafka/routing/features/active_job/contracts/topic.rb +44 -0
- data/lib/karafka/routing/features/active_job/proxy.rb +14 -0
- data/lib/karafka/routing/features/base/expander.rb +8 -2
- data/lib/karafka/routing/features/base.rb +4 -2
- data/lib/karafka/routing/features/dead_letter_queue/contracts/topic.rb +46 -0
- data/lib/karafka/routing/features/declaratives/contracts/topic.rb +33 -0
- data/lib/karafka/routing/features/manual_offset_management/contracts/topic.rb +27 -0
- data/lib/karafka/routing/router.rb +0 -11
- data/lib/karafka/routing/subscription_group.rb +9 -0
- data/lib/karafka/routing/topic.rb +5 -0
- data/lib/karafka/server.rb +9 -4
- data/lib/karafka/setup/config.rb +45 -0
- data/lib/karafka/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +37 -15
- metadata.gz.sig +0 -0
- data/lib/karafka/pro/routing/features/dead_letter_queue/contract.rb +0 -50
- data/lib/karafka/pro/routing/features/expiring/contract.rb +0 -38
- data/lib/karafka/pro/routing/features/pausing/contract.rb +0 -48
- data/lib/karafka/pro/routing/features/throttling/contract.rb +0 -41
- data/lib/karafka/pro/routing/features/virtual_partitions/contract.rb +0 -52
- data/lib/karafka/routing/features/active_job/contract.rb +0 -41
- data/lib/karafka/routing/features/dead_letter_queue/contract.rb +0 -42
- data/lib/karafka/routing/features/declaratives/contract.rb +0 -30
- data/lib/karafka/routing/features/manual_offset_management/contract.rb +0 -24
@@ -0,0 +1,46 @@
|
|
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 Patterns < Base
|
19
|
+
# Namespace for patterns related contracts
|
20
|
+
module Contracts
|
21
|
+
# Contract used to validate pattern data
|
22
|
+
class Pattern < 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('pattern')
|
29
|
+
|
30
|
+
required(:regexp) { |val| val.is_a?(Regexp) }
|
31
|
+
|
32
|
+
required(:regexp_string) do |val|
|
33
|
+
val.is_a?(String) && val.start_with?('^') && val.size >= 2
|
34
|
+
end
|
35
|
+
|
36
|
+
required(:name) do |val|
|
37
|
+
val.is_a?(String) && Karafka::Contracts::TOPIC_REGEXP.match?(val)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
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 Patterns < Base
|
19
|
+
# Namespace for patterns feature contracts
|
20
|
+
module Contracts
|
21
|
+
# Contract to validate configuration of the patterns 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(:patterns) do
|
32
|
+
required(:active) { |val| [true, false].include?(val) }
|
33
|
+
required(:type) { |val| %i[matcher discovered regular].include?(val) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,68 @@
|
|
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 Patterns < Base
|
19
|
+
# Detects if a given topic matches any of the patterns and if so, injects it into the
|
20
|
+
# given subscription group routing
|
21
|
+
#
|
22
|
+
# @note This is NOT thread-safe and should run in a thread-safe context that warranties
|
23
|
+
# that there won't be any race conditions
|
24
|
+
class Detector
|
25
|
+
# Checks if the provided topic matches any of the patterns and when detected, expands
|
26
|
+
# the routing with it.
|
27
|
+
#
|
28
|
+
# @param sg_topics [Array<Karafka::Routing::Topic>] given subscription group routing
|
29
|
+
# topics.
|
30
|
+
# @param new_topic [String] new topic that we have detected
|
31
|
+
def expand(sg_topics, new_topic)
|
32
|
+
sg_topics
|
33
|
+
.map(&:patterns)
|
34
|
+
.select(&:active?)
|
35
|
+
.select(&:matcher?)
|
36
|
+
.map(&:pattern)
|
37
|
+
.then { |pts| pts.empty? ? return : pts }
|
38
|
+
.then { |pts| Patterns.new(pts) }
|
39
|
+
.find(new_topic)
|
40
|
+
.then { |pattern| pattern || return }
|
41
|
+
.then { |pattern| install(pattern, new_topic, sg_topics) }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Adds the discovered topic into the routing
|
47
|
+
#
|
48
|
+
# @param pattern [Karafka::Pro::Routing::Features::Patterns::Pattern] matched pattern
|
49
|
+
# @param discovered_topic [String] topic that we discovered that should be part of the
|
50
|
+
# routing from now on.
|
51
|
+
# @param sg_topics [Array<Karafka::Routing::Topic>]
|
52
|
+
def install(pattern, discovered_topic, sg_topics)
|
53
|
+
consumer_group = pattern.topic.consumer_group
|
54
|
+
|
55
|
+
# Build new topic and register within the consumer group
|
56
|
+
topic = consumer_group.public_send(:topic=, discovered_topic, &pattern.config)
|
57
|
+
topic.patterns(active: true, type: :discovered)
|
58
|
+
|
59
|
+
# Inject into subscription group topics array always, so everything is reflected
|
60
|
+
# there but since it is not active, will not be picked
|
61
|
+
sg_topics << topic
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,81 @@
|
|
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 Patterns < Base
|
19
|
+
# Karafka topic pattern object
|
20
|
+
# It represents a topic that is not yet materialized and that contains a name that is a
|
21
|
+
# regexp and not a "real" value. Underneath we define a dynamic topic, that is not
|
22
|
+
# active, that can be a subject to normal flow validations, etc.
|
23
|
+
class Pattern
|
24
|
+
# Pattern regexp
|
25
|
+
attr_accessor :regexp
|
26
|
+
|
27
|
+
# Each pattern has its own "topic" that we use as a routing reference that we define
|
28
|
+
# with non-existing topic for the routing to correctly pick it up for operations
|
29
|
+
# Virtual topic name for initial subscription
|
30
|
+
attr_reader :name
|
31
|
+
|
32
|
+
# Associated created virtual topic reference
|
33
|
+
attr_accessor :topic
|
34
|
+
|
35
|
+
# Config for real-topic configuration during injection
|
36
|
+
attr_reader :config
|
37
|
+
|
38
|
+
# @param name [String, Symbol, nil] name or the regexp for building the topic name or
|
39
|
+
# nil if we want to make it based on the regexp content
|
40
|
+
# @param regexp [Regexp] regular expression to match topics
|
41
|
+
# @param config [Proc] config for topic bootstrap
|
42
|
+
def initialize(name, regexp, config)
|
43
|
+
@regexp = regexp
|
44
|
+
# This name is also used as the underlying matcher topic name
|
45
|
+
#
|
46
|
+
# It can be used provided by the user in case user wants to use exclusions of topics
|
47
|
+
# or we can generate it if irrelevant.
|
48
|
+
#
|
49
|
+
# We generate it based on the regexp so within the same consumer group they are
|
50
|
+
# always unique (checked by topic validations)
|
51
|
+
#
|
52
|
+
# This will not prevent users from creating a different regexps matching the same
|
53
|
+
# topic but this minimizes simple mistakes
|
54
|
+
#
|
55
|
+
# This sub-part of sh1 should be unique enough and short-enough to use it here
|
56
|
+
digest = Digest::SHA1.hexdigest(regexp.source)[8..16]
|
57
|
+
@name = name ? name.to_s : "karafka-pattern-#{digest}"
|
58
|
+
@config = config
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [String] defined regexp representation as a string that is compatible with
|
62
|
+
# librdkafka expectations. We use it as a subscription name for initial patterns
|
63
|
+
# subscription start.
|
64
|
+
def regexp_string
|
65
|
+
"^#{regexp.source}"
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Hash] hash representation of this routing pattern
|
69
|
+
def to_h
|
70
|
+
{
|
71
|
+
regexp: regexp,
|
72
|
+
name: name,
|
73
|
+
regexp_string: regexp_string
|
74
|
+
}.freeze
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -15,20 +15,17 @@ module Karafka
|
|
15
15
|
module Pro
|
16
16
|
module Routing
|
17
17
|
module Features
|
18
|
-
class
|
19
|
-
#
|
20
|
-
class
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
nested(:delaying) do
|
30
|
-
required(:active) { |val| [true, false].include?(val) }
|
31
|
-
required(:delay) { |val| val.nil? || (val.is_a?(Integer) && val.positive?) }
|
18
|
+
class Patterns < Base
|
19
|
+
# Representation of groups of topics
|
20
|
+
class Patterns < ::Karafka::Routing::Topics
|
21
|
+
# Finds first pattern matching given topic name
|
22
|
+
#
|
23
|
+
# @param topic_name [String] topic name that may match a pattern
|
24
|
+
# @return [Karafka::Routing::Pattern, nil] pattern or nil if not found
|
25
|
+
# @note Please keep in mind, that there may be many patterns matching given topic name
|
26
|
+
# and we always pick the first one (defined first)
|
27
|
+
def find(topic_name)
|
28
|
+
@accumulator.find { |pattern| pattern.regexp =~ topic_name }
|
32
29
|
end
|
33
30
|
end
|
34
31
|
end
|
@@ -0,0 +1,50 @@
|
|
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 Patterns < Base
|
19
|
+
# Patterns feature topic extensions
|
20
|
+
module Topic
|
21
|
+
# @return [String] subscription name or the regexp string representing matching of
|
22
|
+
# new topics that should be detected.
|
23
|
+
def subscription_name
|
24
|
+
patterns.active? && patterns.matcher? ? patterns.pattern.regexp_string : super
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param active [Boolean] is this topic active member of patterns
|
28
|
+
# @param type [Symbol] type of topic taking part in pattern matching
|
29
|
+
# @param pattern [Regexp] regular expression for matching
|
30
|
+
def patterns(active: false, type: :regular, pattern: nil)
|
31
|
+
@patterns ||= Config.new(active: active, type: type, pattern: pattern)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Boolean] is this topic a member of patterns
|
35
|
+
def patterns?
|
36
|
+
patterns.active?
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Hash] topic with all its native configuration options plus patterns
|
40
|
+
def to_h
|
41
|
+
super.merge(
|
42
|
+
patterns: patterns.to_h
|
43
|
+
).freeze
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,53 @@
|
|
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 Patterns < Base
|
19
|
+
# Patterns feature topic extensions
|
20
|
+
module Topics
|
21
|
+
# Finds topic by its name in a more extensive way than the regular. Regular uses the
|
22
|
+
# pre-existing topics definitions. This extension also runs the expansion based on
|
23
|
+
# defined routing patterns (if any)
|
24
|
+
#
|
25
|
+
# If topic does not exist, it will try to run discovery in case there are patterns
|
26
|
+
# defined that would match it.
|
27
|
+
# This allows us to support lookups for newly appearing topics based on their regexp
|
28
|
+
# patterns.
|
29
|
+
#
|
30
|
+
# @param topic_name [String] topic name
|
31
|
+
# @return [Karafka::Routing::Topic]
|
32
|
+
# @raise [Karafka::Errors::TopicNotFoundError] this should never happen. If you see it,
|
33
|
+
# please create an issue.
|
34
|
+
#
|
35
|
+
# @note This method should not be used in context of finding multiple missing topics in
|
36
|
+
# loops because it catches exceptions and attempts to expand routes. If this is used
|
37
|
+
# in a loop for lookups on thousands of topics with detector expansion, this may
|
38
|
+
# be slow. It should be used in the context where newly discovered topics are found
|
39
|
+
# and should by design match a pattern. For quick lookups on batches of topics, it
|
40
|
+
# is recommended to use a custom built lookup with conditional expander.
|
41
|
+
def find(topic_name)
|
42
|
+
super
|
43
|
+
rescue Karafka::Errors::TopicNotFoundError
|
44
|
+
Detector.new.expand(self, topic_name)
|
45
|
+
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
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
|
+
# Dynamic topics builder feature.
|
19
|
+
#
|
20
|
+
# Allows you to define patterns in routes that would then automatically subscribe and
|
21
|
+
# start consuming new topics.
|
22
|
+
#
|
23
|
+
# This feature works by injecting a topic that represents a regexp subscription (matcher)
|
24
|
+
# that at the same time holds the builder block for full config of a newly detected topic.
|
25
|
+
#
|
26
|
+
# We inject a virtual topic to hold settings but also to be able to run validations
|
27
|
+
# during boot to ensure consistency of the pattern base setup.
|
28
|
+
class Patterns < Base
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,51 @@
|
|
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 Pausing < Base
|
19
|
+
# Namespace for pausing feature
|
20
|
+
module Contracts
|
21
|
+
# Contract to make sure, that the pause settings on a per topic basis are as expected
|
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
|
+
|
30
|
+
required(:pause_timeout) { |val| val.is_a?(Integer) && val.positive? }
|
31
|
+
required(:pause_max_timeout) { |val| val.is_a?(Integer) && val.positive? }
|
32
|
+
required(:pause_with_exponential_backoff) { |val| [true, false].include?(val) }
|
33
|
+
|
34
|
+
virtual do |data, errors|
|
35
|
+
next unless errors.empty?
|
36
|
+
|
37
|
+
pause_timeout = data.fetch(:pause_timeout)
|
38
|
+
pause_max_timeout = data.fetch(:pause_max_timeout)
|
39
|
+
|
40
|
+
next if pause_timeout <= pause_max_timeout
|
41
|
+
|
42
|
+
[[%i[pause_timeout], :max_timeout_vs_pause_max_timeout]]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
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 Throttling < Base
|
19
|
+
# Namespace for throttling contracts
|
20
|
+
module Contracts
|
21
|
+
# Rules around throttling settings
|
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(:throttling) do
|
32
|
+
required(:active) { |val| [true, false].include?(val) }
|
33
|
+
required(:interval) { |val| val.is_a?(Integer) && val.positive? }
|
34
|
+
required(:limit) do |val|
|
35
|
+
(val.is_a?(Integer) || val == Float::INFINITY) && val.positive?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,55 @@
|
|
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 VirtualPartitions < Base
|
19
|
+
# Namespace for VP contracts
|
20
|
+
module Contracts
|
21
|
+
# Rules around virtual partitions
|
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(:virtual_partitions) do
|
32
|
+
required(:active) { |val| [true, false].include?(val) }
|
33
|
+
required(:partitioner) { |val| val.nil? || val.respond_to?(:call) }
|
34
|
+
required(:max_partitions) { |val| val.is_a?(Integer) && val >= 1 }
|
35
|
+
end
|
36
|
+
|
37
|
+
# When virtual partitions are defined, partitioner needs to respond to `#call` and it
|
38
|
+
# cannot be nil
|
39
|
+
virtual do |data, errors|
|
40
|
+
next unless errors.empty?
|
41
|
+
|
42
|
+
virtual_partitions = data[:virtual_partitions]
|
43
|
+
|
44
|
+
next unless virtual_partitions[:active]
|
45
|
+
next if virtual_partitions[:partitioner].respond_to?(:call)
|
46
|
+
|
47
|
+
[[%i[virtual_partitions partitioner], :respond_to_call]]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -55,7 +55,7 @@ module Karafka
|
|
55
55
|
def subscription_group=(name = SubscriptionGroup.id, &block)
|
56
56
|
# We cast it here, so the routing supports symbol based but that's anyhow later on
|
57
57
|
# validated as a string
|
58
|
-
@current_subscription_group_id = name
|
58
|
+
@current_subscription_group_id = name.to_s
|
59
59
|
|
60
60
|
Proxy.new(self, &block)
|
61
61
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
module Routing
|
5
|
+
module Features
|
6
|
+
class ActiveJob < Base
|
7
|
+
# This feature validation contracts
|
8
|
+
module Contracts
|
9
|
+
# Rules around using ActiveJob routing - basically you need to have ActiveJob available
|
10
|
+
# in order to be able to use active job routing
|
11
|
+
class Topic < Karafka::Contracts::Base
|
12
|
+
configure do |config|
|
13
|
+
config.error_messages = YAML.safe_load(
|
14
|
+
File.read(
|
15
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
|
16
|
+
)
|
17
|
+
).fetch('en').fetch('validations').fetch('topic')
|
18
|
+
end
|
19
|
+
|
20
|
+
virtual do |data, errors|
|
21
|
+
next unless errors.empty?
|
22
|
+
next unless data[:active_job][:active]
|
23
|
+
# One should not define active job jobs without ActiveJob being available for usage
|
24
|
+
next if Object.const_defined?('ActiveJob::Base')
|
25
|
+
|
26
|
+
[[%i[consumer], :active_job_missing]]
|
27
|
+
end
|
28
|
+
|
29
|
+
# ActiveJob needs to always run with manual offset management
|
30
|
+
# Automatic offset management cannot work with ActiveJob. Otherwise we could mark as
|
31
|
+
# consumed jobs that did not run because of shutdown.
|
32
|
+
virtual do |data, errors|
|
33
|
+
next unless errors.empty?
|
34
|
+
next unless data[:active_job][:active]
|
35
|
+
next if data[:manual_offset_management][:active]
|
36
|
+
|
37
|
+
[[%i[manual_offset_management], :must_be_enabled]]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -30,15 +30,21 @@ module Karafka
|
|
30
30
|
scope = @scope
|
31
31
|
|
32
32
|
Module.new do
|
33
|
-
# Runs validations related to this feature on a
|
33
|
+
# Runs validations related to this feature on a routing resources
|
34
34
|
#
|
35
35
|
# @param block [Proc] routing defining block
|
36
36
|
define_method :draw do |&block|
|
37
37
|
result = super(&block)
|
38
38
|
|
39
39
|
each do |consumer_group|
|
40
|
+
if scope::Contracts.const_defined?('ConsumerGroup', false)
|
41
|
+
scope::Contracts::ConsumerGroup.new.validate!(consumer_group.to_h)
|
42
|
+
end
|
43
|
+
|
44
|
+
next unless scope::Contracts.const_defined?('Topic', false)
|
45
|
+
|
40
46
|
consumer_group.topics.each do |topic|
|
41
|
-
scope::
|
47
|
+
scope::Contracts::Topic.new.validate!(topic.to_h)
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
@@ -14,9 +14,11 @@ module Karafka
|
|
14
14
|
# Extends topic and builder with given feature API
|
15
15
|
def activate
|
16
16
|
Topic.prepend(self::Topic) if const_defined?('Topic', false)
|
17
|
-
|
17
|
+
Topics.prepend(self::Topics) if const_defined?('Topics', false)
|
18
|
+
ConsumerGroup.prepend(self::ConsumerGroup) if const_defined?('ConsumerGroup', false)
|
19
|
+
Proxy.prepend(self::Proxy) if const_defined?('Proxy', false)
|
18
20
|
Builder.prepend(self::Builder) if const_defined?('Builder', false)
|
19
|
-
Builder.prepend(Base::Expander.new(self)) if const_defined?('
|
21
|
+
Builder.prepend(Base::Expander.new(self)) if const_defined?('Contracts', false)
|
20
22
|
end
|
21
23
|
|
22
24
|
# Loads all the features and activates them
|