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,111 @@
|
|
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 Contracts
|
17
|
+
# Contract for validating correctness of the server cli command options.
|
18
|
+
# It differs slightly from the OSS one because it is aware of the routing patterns
|
19
|
+
class ServerCliOptions < ::Karafka::Contracts::ServerCliOptions
|
20
|
+
configure do |config|
|
21
|
+
config.error_messages = YAML.safe_load(
|
22
|
+
File.read(
|
23
|
+
File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
|
24
|
+
)
|
25
|
+
).fetch('en').fetch('validations').fetch('server_cli_options')
|
26
|
+
end
|
27
|
+
|
28
|
+
%i[
|
29
|
+
include
|
30
|
+
exclude
|
31
|
+
].each do |action|
|
32
|
+
optional(:"#{action}_consumer_groups") { |cg| cg.is_a?(Array) }
|
33
|
+
optional(:"#{action}_subscription_groups") { |sg| sg.is_a?(Array) }
|
34
|
+
optional(:"#{action}_topics") { |topics| topics.is_a?(Array) }
|
35
|
+
|
36
|
+
virtual do |data, errors|
|
37
|
+
next unless errors.empty?
|
38
|
+
|
39
|
+
value = data.fetch(:"#{action}_consumer_groups")
|
40
|
+
|
41
|
+
# If there were no consumer_groups declared in the server cli, it means that we will
|
42
|
+
# run all of them and no need to validate them here at all
|
43
|
+
next if value.empty?
|
44
|
+
next if (value - Karafka::App.consumer_groups.map(&:name)).empty?
|
45
|
+
|
46
|
+
# Found unknown consumer groups
|
47
|
+
[[[:"#{action}_consumer_groups"], :consumer_groups_inclusion]]
|
48
|
+
end
|
49
|
+
|
50
|
+
virtual do |data, errors|
|
51
|
+
next unless errors.empty?
|
52
|
+
|
53
|
+
value = data.fetch(:"#{action}_subscription_groups")
|
54
|
+
|
55
|
+
# If there were no subscription_groups declared in the server cli, it means that we
|
56
|
+
# will run all of them and no need to validate them here at all
|
57
|
+
next if value.empty?
|
58
|
+
|
59
|
+
subscription_groups = Karafka::App
|
60
|
+
.consumer_groups
|
61
|
+
.map(&:subscription_groups)
|
62
|
+
.flatten
|
63
|
+
.map(&:name)
|
64
|
+
|
65
|
+
next if (value - subscription_groups).empty?
|
66
|
+
|
67
|
+
# Found unknown subscription groups
|
68
|
+
[[[:"#{action}_subscription_groups"], :subscription_groups_inclusion]]
|
69
|
+
end
|
70
|
+
|
71
|
+
virtual do |data, errors|
|
72
|
+
next unless errors.empty?
|
73
|
+
|
74
|
+
value = data.fetch(:"#{action}_topics")
|
75
|
+
|
76
|
+
# If there were no topics declared in the server cli, it means that we will
|
77
|
+
# run all of them and no need to validate them here at all
|
78
|
+
next if value.empty?
|
79
|
+
|
80
|
+
topics = Karafka::App
|
81
|
+
.consumer_groups
|
82
|
+
.map(&:subscription_groups)
|
83
|
+
.flatten
|
84
|
+
.map(&:topics)
|
85
|
+
.map { |gtopics| gtopics.map(&:name) }
|
86
|
+
.flatten
|
87
|
+
|
88
|
+
next if (value - topics).empty?
|
89
|
+
|
90
|
+
# If there are any patterns defined, we cannot report on topics inclusions because
|
91
|
+
# topics may be added during boot or runtime. We go with simple assumption:
|
92
|
+
# if there are patterns defined, we do not check the inclusions at all
|
93
|
+
next unless Karafka::App.consumer_groups.map(&:patterns).flatten.empty?
|
94
|
+
|
95
|
+
# Found unknown topics
|
96
|
+
[[[:"#{action}_topics"], :topics_inclusion]]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Makes sure we have anything to subscribe to when we start the server
|
101
|
+
virtual do |_, errors|
|
102
|
+
next unless errors.empty?
|
103
|
+
|
104
|
+
next unless Karafka::App.subscription_groups.empty?
|
105
|
+
|
106
|
+
[[%i[include_topics], :topics_missing]]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -16,8 +16,11 @@ module Karafka
|
|
16
16
|
module Encryption
|
17
17
|
# Encryption related errors
|
18
18
|
module Errors
|
19
|
+
# Base for all the encryption errors
|
20
|
+
BaseError = Class.new(::Karafka::Errors::BaseError)
|
21
|
+
|
19
22
|
# Raised when we have encountered encryption key with version we do not have
|
20
|
-
PrivateKeyNotFound = Class.new(
|
23
|
+
PrivateKeyNotFound = Class.new(BaseError)
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
data/lib/karafka/pro/loader.rb
CHANGED
@@ -66,10 +66,12 @@ module Karafka
|
|
66
66
|
|
67
67
|
private
|
68
68
|
|
69
|
-
# @return [Array<Module>] extra non-routing related pro features
|
69
|
+
# @return [Array<Module>] extra non-routing related pro features and routing components
|
70
|
+
# that need to have some special configuration stuff injected into config, etc
|
70
71
|
def features
|
71
72
|
[
|
72
|
-
Encryption
|
73
|
+
Encryption,
|
74
|
+
Cleaner
|
73
75
|
]
|
74
76
|
end
|
75
77
|
|
@@ -78,6 +80,8 @@ module Karafka
|
|
78
80
|
def reconfigure(config)
|
79
81
|
icfg = config.internal
|
80
82
|
|
83
|
+
icfg.cli.contract = Contracts::ServerCliOptions.new
|
84
|
+
|
81
85
|
icfg.processing.coordinator_class = Processing::Coordinator
|
82
86
|
icfg.processing.partitioner_class = Processing::Partitioner
|
83
87
|
icfg.processing.scheduler = Processing::Scheduler.new
|
@@ -74,6 +74,12 @@ module Karafka
|
|
74
74
|
# @param skippable_message [Array<Karafka::Messages::Message>] message we want to
|
75
75
|
# dispatch to DLQ
|
76
76
|
def dispatch_to_dlq(skippable_message)
|
77
|
+
# DLQ should never try to dispatch a message that was cleaned. It message was
|
78
|
+
# cleaned, we will not have all the needed data. If you see this error, it means
|
79
|
+
# that your processing flow is not as expected and you have cleaned message that
|
80
|
+
# should not be cleaned as it should go to the DLQ
|
81
|
+
raise(Cleaner::Errors::MessageCleanedError) if skippable_message.cleaned?
|
82
|
+
|
77
83
|
producer.produce_async(
|
78
84
|
build_dlq_message(
|
79
85
|
skippable_message
|
@@ -0,0 +1,45 @@
|
|
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 ActiveJob < Base
|
19
|
+
# Pro ActiveJob builder expansions
|
20
|
+
module Builder
|
21
|
+
# This method simplifies routes definition for ActiveJob patterns / queues by
|
22
|
+
# auto-injecting the consumer class and other things needed
|
23
|
+
#
|
24
|
+
# @param regexp_or_name [String, Symbol, Regexp] pattern name or regexp to use
|
25
|
+
# auto-generated regexp names
|
26
|
+
# @param regexp [Regexp, nil] activejob regexp pattern or nil when regexp is provided
|
27
|
+
# as the first argument
|
28
|
+
# @param block [Proc] block that we can use for some extra configuration
|
29
|
+
def active_job_pattern(regexp_or_name, regexp = nil, &block)
|
30
|
+
pattern(regexp_or_name, regexp) do
|
31
|
+
consumer App.config.internal.active_job.consumer_class
|
32
|
+
active_job true
|
33
|
+
manual_offset_management true
|
34
|
+
|
35
|
+
next unless block
|
36
|
+
|
37
|
+
instance_eval(&block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,26 @@
|
|
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
|
+
# Small extension to make ActiveJob work with pattern matching.
|
19
|
+
# Since our `#active_job_topic` is just a topic wrapper, we can introduce a similar
|
20
|
+
# `#active_job_pattern` to align with pattern building
|
21
|
+
class ActiveJob < Base
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
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 DeadLetterQueue < Base
|
19
|
+
# Namespace for DLQ contracts
|
20
|
+
module Contracts
|
21
|
+
# Extended rules for dead letter queue 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
|
+
# Make sure that when we use virtual partitions with DLQ, at least one retry is set
|
32
|
+
# We cannot use VP with DLQ without retries as we in order to provide ordering
|
33
|
+
# warranties on errors with VP, we need to collapse the VPs concurrency and retry
|
34
|
+
# without any indeterministic work
|
35
|
+
virtual do |data, errors|
|
36
|
+
next unless errors.empty?
|
37
|
+
|
38
|
+
dead_letter_queue = data[:dead_letter_queue]
|
39
|
+
virtual_partitions = data[:virtual_partitions]
|
40
|
+
|
41
|
+
next unless dead_letter_queue[:active]
|
42
|
+
next unless virtual_partitions[:active]
|
43
|
+
next if dead_letter_queue[:max_retries].positive?
|
44
|
+
|
45
|
+
[[%i[dead_letter_queue], :with_virtual_partitions]]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
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 Delaying < Base
|
19
|
+
# Namespace for delaying 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(:delaying) do
|
32
|
+
required(:active) { |val| [true, false].include?(val) }
|
33
|
+
required(:delay) { |val| val.nil? || (val.is_a?(Integer) && val.positive?) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
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 Expiring < Base
|
19
|
+
# Namespace for expiring messages 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(:expiring) do
|
32
|
+
required(:active) { |val| [true, false].include?(val) }
|
33
|
+
required(:ttl) { |val| val.nil? || (val.is_a?(Integer) && val.positive?) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
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 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
|