karafka 2.1.12 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|