karafka 2.1.13 → 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 +35 -0
- data/Gemfile.lock +1 -1
- 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/pro/contracts/base.rb +23 -0
- data/lib/karafka/pro/contracts/server_cli_options.rb +111 -0
- data/lib/karafka/pro/loader.rb +4 -1
- 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 +32 -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,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 Filtering < Base
|
19
|
+
# Namespace for filtering feature contracts
|
20
|
+
module Contracts
|
21
|
+
# Contract to validate configuration of the filtering 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(:filtering) do
|
32
|
+
required(:active) { |val| [true, false].include?(val) }
|
33
|
+
|
34
|
+
required(:factories) do |val|
|
35
|
+
val.is_a?(Array) && val.all? { |factory| factory.respond_to?(:call) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -16,18 +16,21 @@ module Karafka
|
|
16
16
|
module Routing
|
17
17
|
module Features
|
18
18
|
class LongRunningJob < Base
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
19
|
+
# Namespace for LRJ contracts
|
20
|
+
module Contracts
|
21
|
+
# Rules around long-running job 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
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
+
nested(:long_running_job) do
|
32
|
+
required(:active) { |val| [true, false].include?(val) }
|
33
|
+
end
|
31
34
|
end
|
32
35
|
end
|
33
36
|
end
|
@@ -15,22 +15,19 @@ module Karafka
|
|
15
15
|
module Pro
|
16
16
|
module Routing
|
17
17
|
module Features
|
18
|
-
class
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
required(:factories) do |val|
|
33
|
-
val.is_a?(Array) && val.all? { |factory| factory.respond_to?(:call) }
|
18
|
+
class Patterns < Base
|
19
|
+
# Expansions for the routing builder
|
20
|
+
module Builder
|
21
|
+
# Allows us to define the simple routing pattern matching
|
22
|
+
#
|
23
|
+
# @param regexp_or_name [Symbol, String, Regexp] name of the pattern or regexp for
|
24
|
+
# automatic-based named patterns
|
25
|
+
# @param regexp [Regexp, nil] nil if we use auto-generated name based on the regexp or
|
26
|
+
# the regexp if we used named patterns
|
27
|
+
# @param block [Proc]
|
28
|
+
def pattern(regexp_or_name, regexp = nil, &block)
|
29
|
+
consumer_group('app') do
|
30
|
+
pattern(regexp_or_name, regexp, &block)
|
34
31
|
end
|
35
32
|
end
|
36
33
|
end
|
@@ -0,0 +1,54 @@
|
|
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
|
+
# Holds pattern info reference
|
19
|
+
# Type is set to:
|
20
|
+
# `:regular` - in case patterns are not used and topic is just a regular existing topic
|
21
|
+
# matched directly based on the name
|
22
|
+
# `:discovered` - in case it is a real topic on which we started to listed
|
23
|
+
# `:matcher` - represents a regular expression used by librdkafka
|
24
|
+
class Patterns < Base
|
25
|
+
# Config for pattern based topic
|
26
|
+
# Only pattern related topics are active in this context
|
27
|
+
Config = Struct.new(
|
28
|
+
:active,
|
29
|
+
:type,
|
30
|
+
:pattern,
|
31
|
+
keyword_init: true
|
32
|
+
) do
|
33
|
+
alias_method :active?, :active
|
34
|
+
|
35
|
+
# @return [Boolean] is this a matcher topic
|
36
|
+
def matcher?
|
37
|
+
type == :matcher
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Boolean] is this a discovered topic
|
41
|
+
def discovered?
|
42
|
+
type == :discovered
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Boolean] is this a regular topic
|
46
|
+
def regular?
|
47
|
+
type == :regular
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
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
|
+
# Expansion of the consumer groups routing component to work with patterns
|
20
|
+
module ConsumerGroup
|
21
|
+
# @param args [Object] whatever consumer group accepts
|
22
|
+
def initialize(*args)
|
23
|
+
super
|
24
|
+
@patterns = Patterns.new([])
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [::Karafka::Pro::Routing::Features::Patterns::Patterns] created patterns
|
28
|
+
def patterns
|
29
|
+
@patterns
|
30
|
+
end
|
31
|
+
|
32
|
+
# Creates the pattern for topic matching with appropriate virtual topic
|
33
|
+
# @param regexp_or_name [Symbol, String, Regexp] name of the pattern or regexp for
|
34
|
+
# automatic-based named patterns
|
35
|
+
# @param regexp [Regexp, nil] nil if we use auto-generated name based on the regexp or
|
36
|
+
# the regexp if we used named patterns
|
37
|
+
# @param block [Proc] appropriate underlying topic settings
|
38
|
+
def pattern=(regexp_or_name, regexp = nil, &block)
|
39
|
+
# This code allows us to have a nice nameless (automatic-named) patterns that do not
|
40
|
+
# have to be explicitly named. However if someone wants to use names for exclusions
|
41
|
+
# it can be done by providing both
|
42
|
+
if regexp_or_name.is_a?(Regexp)
|
43
|
+
name = nil
|
44
|
+
regexp = regexp_or_name
|
45
|
+
else
|
46
|
+
name = regexp_or_name
|
47
|
+
end
|
48
|
+
|
49
|
+
pattern = Pattern.new(name, regexp, block)
|
50
|
+
virtual_topic = public_send(:topic=, pattern.name, &block)
|
51
|
+
# Indicate the nature of this topic (matcher)
|
52
|
+
virtual_topic.patterns(active: true, type: :matcher, pattern: pattern)
|
53
|
+
pattern.topic = virtual_topic
|
54
|
+
@patterns << pattern
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Hash] consumer group with patterns injected
|
58
|
+
def to_h
|
59
|
+
super.merge(
|
60
|
+
patterns: patterns.map(&:to_h)
|
61
|
+
).freeze
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,62 @@
|
|
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
|
+
module Contracts
|
20
|
+
# Contract to validate configuration of the filtering feature
|
21
|
+
class ConsumerGroup < Karafka::Contracts::Base
|
22
|
+
configure do |config|
|
23
|
+
config.error_messages = YAML.safe_load(
|
24
|
+
File.read(
|
25
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'pro_errors.yml')
|
26
|
+
)
|
27
|
+
).fetch('en').fetch('validations').fetch('consumer_group')
|
28
|
+
|
29
|
+
required(:patterns) { |val| val.is_a?(Array) && val.all? { |el| el.is_a?(Hash) } }
|
30
|
+
|
31
|
+
virtual do |data, errors|
|
32
|
+
next unless errors.empty?
|
33
|
+
|
34
|
+
validator = Pattern.new
|
35
|
+
|
36
|
+
data[:patterns].each do |pattern|
|
37
|
+
validator.validate!(pattern)
|
38
|
+
end
|
39
|
+
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# Make sure, that there are no same regular expressions with different names
|
44
|
+
# in a single consumer group
|
45
|
+
virtual do |data, errors|
|
46
|
+
next unless errors.empty?
|
47
|
+
|
48
|
+
regexp_strings = data[:patterns].map { |pattern| pattern.fetch(:regexp_string) }
|
49
|
+
|
50
|
+
next if regexp_strings.empty?
|
51
|
+
next if regexp_strings.uniq.size == regexp_strings.size
|
52
|
+
|
53
|
+
[[%i[patterns], :regexps_not_unique]]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -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
|