karafka 2.0.0.beta2 → 2.0.0.beta5
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/.github/workflows/ci.yml +18 -15
- data/CHANGELOG.md +49 -0
- data/Gemfile.lock +8 -8
- data/bin/benchmarks +2 -2
- data/bin/integrations +44 -15
- data/bin/scenario +29 -0
- data/bin/{stress → stress_many} +0 -0
- data/bin/stress_one +13 -0
- data/bin/wait_for_kafka +20 -0
- data/docker-compose.yml +28 -11
- data/karafka.gemspec +2 -2
- data/lib/karafka/active_job/routing/extensions.rb +12 -2
- data/lib/karafka/app.rb +2 -1
- data/lib/karafka/base_consumer.rb +75 -45
- data/lib/karafka/connection/client.rb +88 -22
- data/lib/karafka/connection/listener.rb +60 -18
- data/lib/karafka/connection/pauses_manager.rb +8 -0
- data/lib/karafka/connection/rebalance_manager.rb +20 -19
- data/lib/karafka/contracts/config.rb +17 -3
- data/lib/karafka/contracts/server_cli_options.rb +1 -1
- data/lib/karafka/errors.rb +3 -0
- data/lib/karafka/instrumentation/logger_listener.rb +34 -10
- data/lib/karafka/instrumentation/monitor.rb +3 -1
- data/lib/karafka/licenser.rb +26 -7
- data/lib/karafka/pro/active_job/consumer.rb +30 -9
- data/lib/karafka/pro/active_job/dispatcher.rb +9 -9
- data/lib/karafka/pro/active_job/job_options_contract.rb +9 -9
- data/lib/karafka/pro/base_consumer.rb +73 -0
- data/lib/karafka/pro/loader.rb +38 -20
- data/lib/karafka/pro/performance_tracker.rb +9 -9
- data/lib/karafka/pro/processing/coordinator.rb +12 -0
- data/lib/karafka/pro/processing/jobs/consume_non_blocking.rb +10 -11
- data/lib/karafka/pro/processing/jobs_builder.rb +32 -0
- data/lib/karafka/pro/processing/scheduler.rb +56 -0
- data/lib/karafka/pro/routing/extensions.rb +32 -0
- data/lib/karafka/processing/coordinator.rb +84 -0
- data/lib/karafka/processing/coordinators_buffer.rb +58 -0
- data/lib/karafka/processing/executor.rb +23 -9
- data/lib/karafka/processing/executors_buffer.rb +46 -15
- data/lib/karafka/processing/jobs/base.rb +8 -3
- data/lib/karafka/processing/jobs/consume.rb +11 -4
- data/lib/karafka/processing/jobs_builder.rb +29 -0
- data/lib/karafka/processing/result.rb +29 -0
- data/lib/karafka/processing/scheduler.rb +22 -0
- data/lib/karafka/processing/worker.rb +17 -9
- data/lib/karafka/routing/consumer_group.rb +1 -1
- data/lib/karafka/routing/subscription_group.rb +1 -1
- data/lib/karafka/routing/topic.rb +14 -0
- data/lib/karafka/setup/config.rb +19 -9
- data/lib/karafka/status.rb +1 -3
- data/lib/karafka/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +19 -7
- metadata.gz.sig +0 -0
- data/lib/karafka/pro/scheduler.rb +0 -54
- data/lib/karafka/scheduler.rb +0 -20
@@ -30,11 +30,25 @@ module Karafka
|
|
30
30
|
|
31
31
|
# We validate internals just to be sure, that they are present and working
|
32
32
|
required(:internal).schema do
|
33
|
-
required(:routing_builder)
|
34
33
|
required(:status)
|
35
34
|
required(:process)
|
36
|
-
|
37
|
-
required(:
|
35
|
+
|
36
|
+
required(:routing).schema do
|
37
|
+
required(:builder)
|
38
|
+
required(:subscription_groups_builder)
|
39
|
+
end
|
40
|
+
|
41
|
+
required(:processing).schema do
|
42
|
+
required(:jobs_builder)
|
43
|
+
required(:scheduler)
|
44
|
+
required(:coordinator_class)
|
45
|
+
end
|
46
|
+
|
47
|
+
required(:active_job).schema do
|
48
|
+
required(:dispatcher)
|
49
|
+
required(:job_options_contract)
|
50
|
+
required(:consumer_class)
|
51
|
+
end
|
38
52
|
end
|
39
53
|
end
|
40
54
|
|
@@ -12,7 +12,7 @@ module Karafka
|
|
12
12
|
# If there were no consumer_groups declared in the server cli, it means that we will
|
13
13
|
# run all of them and no need to validate them here at all
|
14
14
|
if !value.nil? &&
|
15
|
-
!(value - Karafka::App.config.internal.
|
15
|
+
!(value - Karafka::App.config.internal.routing.builder.map(&:name)).empty?
|
16
16
|
key(:consumer_groups).failure(:consumer_groups_inclusion)
|
17
17
|
end
|
18
18
|
end
|
data/lib/karafka/errors.rb
CHANGED
@@ -47,5 +47,8 @@ module Karafka
|
|
47
47
|
# Used to instrument this error into the error notifications
|
48
48
|
# We do not raise it so we won't crash deployed systems
|
49
49
|
ExpiredLicenseTokenError = Class.new(BaseError)
|
50
|
+
|
51
|
+
# This should never happen. Please open an issue if it does.
|
52
|
+
InvalidCoordinatorState = Class.new(BaseError)
|
50
53
|
end
|
51
54
|
end
|
@@ -15,16 +15,43 @@ module Karafka
|
|
15
15
|
|
16
16
|
# Logs each messages fetching attempt
|
17
17
|
#
|
18
|
-
# @param
|
19
|
-
def on_connection_listener_fetch_loop(
|
20
|
-
|
18
|
+
# @param event [Dry::Events::Event] event details including payload
|
19
|
+
def on_connection_listener_fetch_loop(event)
|
20
|
+
listener = event[:caller]
|
21
|
+
info "[#{listener.id}] Polling messages..."
|
21
22
|
end
|
22
23
|
|
23
24
|
# Logs about messages that we've received from Kafka
|
24
25
|
#
|
25
26
|
# @param event [Dry::Events::Event] event details including payload
|
26
27
|
def on_connection_listener_fetch_loop_received(event)
|
27
|
-
|
28
|
+
listener = event[:caller]
|
29
|
+
time = event[:time]
|
30
|
+
messages_count = event[:messages_buffer].size
|
31
|
+
info "[#{listener.id}] Polled #{messages_count} messages in #{time}ms"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Prints info about the fact that a given job has started
|
35
|
+
#
|
36
|
+
# @param event [Dry::Events::Event] event details including payload
|
37
|
+
def on_worker_process(event)
|
38
|
+
job = event[:job]
|
39
|
+
job_type = job.class.to_s.split('::').last
|
40
|
+
consumer = job.executor.topic.consumer
|
41
|
+
topic = job.executor.topic.name
|
42
|
+
info "[#{job.id}] #{job_type} job for #{consumer} on #{topic} started"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Prints info about the fact that a given job has finished
|
46
|
+
#
|
47
|
+
# @param event [Dry::Events::Event] event details including payload
|
48
|
+
def on_worker_processed(event)
|
49
|
+
job = event[:job]
|
50
|
+
time = event[:time]
|
51
|
+
job_type = job.class.to_s.split('::').last
|
52
|
+
consumer = job.executor.topic.consumer
|
53
|
+
topic = job.executor.topic.name
|
54
|
+
info "[#{job.id}] #{job_type} job for #{consumer} on #{topic} finished in #{time}ms"
|
28
55
|
end
|
29
56
|
|
30
57
|
# Logs info about system signals that Karafka received.
|
@@ -52,16 +79,14 @@ module Karafka
|
|
52
79
|
#
|
53
80
|
# @param _event [Dry::Events::Event] event details including payload
|
54
81
|
def on_app_stopping(_event)
|
55
|
-
|
56
|
-
Thread.new { info 'Stopping Karafka server' }
|
82
|
+
info 'Stopping Karafka server'
|
57
83
|
end
|
58
84
|
|
59
85
|
# Logs info that we stopped the Karafka server.
|
60
86
|
#
|
61
87
|
# @param _event [Dry::Events::Event] event details including payload
|
62
88
|
def on_app_stopped(_event)
|
63
|
-
|
64
|
-
Thread.new { info 'Stopped Karafka server' }
|
89
|
+
info 'Stopped Karafka server'
|
65
90
|
end
|
66
91
|
|
67
92
|
# There are many types of errors that can occur in many places, but we provide a single
|
@@ -95,8 +120,7 @@ module Karafka
|
|
95
120
|
fatal "Runner crashed due to an error: #{error}"
|
96
121
|
fatal details
|
97
122
|
when 'app.stopping.error'
|
98
|
-
|
99
|
-
Thread.new { error 'Forceful Karafka server stop' }
|
123
|
+
error 'Forceful Karafka server stop'
|
100
124
|
when 'librdkafka.error'
|
101
125
|
error "librdkafka internal error occurred: #{error}"
|
102
126
|
error details
|
@@ -22,7 +22,6 @@ module Karafka
|
|
22
22
|
app.stopping
|
23
23
|
app.stopped
|
24
24
|
|
25
|
-
consumer.prepared
|
26
25
|
consumer.consumed
|
27
26
|
consumer.revoked
|
28
27
|
consumer.shutdown
|
@@ -33,6 +32,9 @@ module Karafka
|
|
33
32
|
connection.listener.fetch_loop
|
34
33
|
connection.listener.fetch_loop.received
|
35
34
|
|
35
|
+
worker.process
|
36
|
+
worker.processed
|
37
|
+
|
36
38
|
statistics.emitted
|
37
39
|
|
38
40
|
error.occurred
|
data/lib/karafka/licenser.rb
CHANGED
@@ -33,6 +33,8 @@ module Karafka
|
|
33
33
|
|
34
34
|
return if license_config.expires_on > Date.today
|
35
35
|
|
36
|
+
raise_expired_license_token_in_dev(license_config.expires_on)
|
37
|
+
|
36
38
|
notify_if_license_expired(license_config.expires_on)
|
37
39
|
end
|
38
40
|
|
@@ -53,24 +55,41 @@ module Karafka
|
|
53
55
|
)
|
54
56
|
end
|
55
57
|
|
58
|
+
# Raises an error for test and dev environments if running pro with expired license
|
59
|
+
# We never want to cause any non-dev problems and we should never crash anything else than
|
60
|
+
# tests and development envs.
|
61
|
+
#
|
62
|
+
# @param expires_on [Date] when the license expires
|
63
|
+
def raise_expired_license_token_in_dev(expires_on)
|
64
|
+
env = Karafka::App.env
|
65
|
+
|
66
|
+
return unless env.development? || env.test?
|
67
|
+
|
68
|
+
raise Errors::ExpiredLicenseTokenError.new, expired_message(expires_on)
|
69
|
+
end
|
70
|
+
|
56
71
|
# We do not raise an error here as we don't want to cause any problems to someone that runs
|
57
72
|
# Karafka on production. Error message is enough.
|
58
73
|
#
|
59
74
|
# @param expires_on [Date] when the license expires
|
60
75
|
def notify_if_license_expired(expires_on)
|
61
|
-
|
62
|
-
Your license expired on #{expires_on}.
|
63
|
-
Please reach us at contact@karafka.io or visit https://karafka.io to obtain a valid one.
|
64
|
-
MSG
|
65
|
-
|
66
|
-
Karafka.logger.error(message)
|
76
|
+
Karafka.logger.error(expired_message(expires_on))
|
67
77
|
|
68
78
|
Karafka.monitor.instrument(
|
69
79
|
'error.occurred',
|
70
80
|
caller: self,
|
71
|
-
error: Errors::ExpiredLicenseTokenError.new(
|
81
|
+
error: Errors::ExpiredLicenseTokenError.new(expired_message(expires_on)),
|
72
82
|
type: 'licenser.expired'
|
73
83
|
)
|
74
84
|
end
|
85
|
+
|
86
|
+
# @param expires_on [Date] when the license expires
|
87
|
+
# @return [String] expired message
|
88
|
+
def expired_message(expires_on)
|
89
|
+
<<~MSG.tr("\n", ' ')
|
90
|
+
Your license expired on #{expires_on}.
|
91
|
+
Please reach us at contact@karafka.io or visit https://karafka.io to obtain a valid one.
|
92
|
+
MSG
|
93
|
+
end
|
75
94
|
end
|
76
95
|
end
|
@@ -1,20 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
3
12
|
module Karafka
|
4
13
|
module Pro
|
5
14
|
module ActiveJob
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# repository and their usage requires commercial license agreement.
|
15
|
+
# Pro ActiveJob consumer that is suppose to handle long-running jobs as well as short
|
16
|
+
# running jobs
|
9
17
|
#
|
10
|
-
#
|
18
|
+
# When in LRJ, it will pause a given partition forever and will resume its processing only
|
19
|
+
# when all the jobs are done processing.
|
11
20
|
#
|
12
|
-
#
|
13
|
-
# of
|
21
|
+
# It contains slightly better revocation warranties than the regular blocking consumer as
|
22
|
+
# it can stop processing batch of jobs in the middle after the revocation.
|
23
|
+
class Consumer < Karafka::Pro::BaseConsumer
|
24
|
+
# Runs ActiveJob jobs processing and handles lrj if needed
|
25
|
+
def consume
|
26
|
+
messages.each do |message|
|
27
|
+
# If for any reason we've lost this partition, not worth iterating over new messages
|
28
|
+
# as they are no longer ours
|
29
|
+
break if revoked?
|
30
|
+
break if Karafka::App.stopping?
|
14
31
|
|
15
|
-
|
16
|
-
|
17
|
-
|
32
|
+
::ActiveJob::Base.execute(
|
33
|
+
::ActiveSupport::JSON.decode(message.raw_payload)
|
34
|
+
)
|
35
|
+
|
36
|
+
mark_as_consumed(message)
|
37
|
+
end
|
38
|
+
end
|
18
39
|
end
|
19
40
|
end
|
20
41
|
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
3
12
|
module Karafka
|
4
13
|
module Pro
|
5
14
|
# Karafka Pro ActiveJob components
|
6
15
|
module ActiveJob
|
7
|
-
# This Karafka component is a Pro component.
|
8
|
-
# All of the commercial components are present in the lib/karafka/pro directory of this
|
9
|
-
# repository and their usage requires commercial license agreement.
|
10
|
-
#
|
11
|
-
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
12
|
-
#
|
13
|
-
# By sending a pull request to the pro components, you are agreeing to transfer the copyright
|
14
|
-
# of your code to Maciej Mensfeld.
|
15
|
-
|
16
16
|
# Pro dispatcher that sends the ActiveJob job to a proper topic based on the queue name
|
17
17
|
# and that allows to inject additional options into the producer, effectively allowing for a
|
18
18
|
# much better and more granular control over the dispatch and consumption process.
|
@@ -1,17 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
3
12
|
module Karafka
|
4
13
|
module Pro
|
5
14
|
module ActiveJob
|
6
|
-
# This Karafka component is a Pro component.
|
7
|
-
# All of the commercial components are present in the lib/karafka/pro directory of this
|
8
|
-
# repository and their usage requires commercial license agreement.
|
9
|
-
#
|
10
|
-
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
11
|
-
#
|
12
|
-
# By sending a pull request to the pro components, you are agreeing to transfer the copyright
|
13
|
-
# of your code to Maciej Mensfeld.
|
14
|
-
|
15
15
|
# Contract for validating the options that can be altered with `#karafka_options` per job
|
16
16
|
# class that works with Pro features.
|
17
17
|
class JobOptionsContract < ::Karafka::ActiveJob::JobOptionsContract
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
12
|
+
module Karafka
|
13
|
+
module Pro
|
14
|
+
# Karafka PRO consumer.
|
15
|
+
#
|
16
|
+
# If you use PRO, all your consumers should inherit (indirectly) from it.
|
17
|
+
#
|
18
|
+
# @note In case of using lrj, manual pausing may not be the best idea as resume needs to happen
|
19
|
+
# after each batch is processed.
|
20
|
+
class BaseConsumer < Karafka::BaseConsumer
|
21
|
+
# Pause for tops 31 years
|
22
|
+
MAX_PAUSE_TIME = 1_000_000_000_000
|
23
|
+
|
24
|
+
private_constant :MAX_PAUSE_TIME
|
25
|
+
|
26
|
+
# Pauses processing of a given partition until we're done with the processing
|
27
|
+
# This ensures, that we can easily poll not reaching the `max.poll.interval`
|
28
|
+
def on_before_consume
|
29
|
+
# Pause at the first message in a batch. That way in case of a crash, we will not loose
|
30
|
+
# any messages
|
31
|
+
return unless topic.long_running_job?
|
32
|
+
|
33
|
+
pause(messages.first.offset, MAX_PAUSE_TIME)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Runs extra logic after consumption that is related to handling long running jobs
|
37
|
+
# @note This overwrites the '#on_after_consume' from the base consumer
|
38
|
+
def on_after_consume
|
39
|
+
# Nothing to do if we lost the partition
|
40
|
+
return if revoked?
|
41
|
+
|
42
|
+
if @coordinator.success?
|
43
|
+
coordinator.pause_tracker.reset
|
44
|
+
|
45
|
+
# We use the non-blocking one here. If someone needs the blocking one, can implement it
|
46
|
+
# with manual offset management
|
47
|
+
# Mark as consumed only if manual offset management is not on
|
48
|
+
mark_as_consumed(messages.last) unless topic.manual_offset_management?
|
49
|
+
|
50
|
+
# We check it twice as marking could change this state
|
51
|
+
return if revoked?
|
52
|
+
|
53
|
+
# If this is not a long running job there is nothing for us to do here
|
54
|
+
return unless topic.long_running_job?
|
55
|
+
|
56
|
+
# Once processing is done, we move to the new offset based on commits
|
57
|
+
# Here, in case manual offset management is off, we have the new proper offset of a
|
58
|
+
# first message from another batch from `@seek_offset`. If manual offset management
|
59
|
+
# is on, we move to place where the user indicated it was finished. This can create an
|
60
|
+
# interesting (yet valid) corner case, where with manual offset management on and no
|
61
|
+
# marking as consumed, we end up with an infinite loop processing same messages over and
|
62
|
+
# over again
|
63
|
+
seek(@seek_offset || messages.first.offset)
|
64
|
+
|
65
|
+
resume
|
66
|
+
else
|
67
|
+
# If processing failed, we need to pause
|
68
|
+
pause(@seek_offset || messages.first.offset)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/karafka/pro/loader.rb
CHANGED
@@ -1,34 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
3
12
|
module Karafka
|
4
13
|
module Pro
|
5
|
-
# This Karafka component is a Pro component.
|
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
|
12
|
-
# of your code to Maciej Mensfeld.
|
13
|
-
|
14
14
|
# Loader requires and loads all the pro components only when they are needed
|
15
15
|
class Loader
|
16
|
+
# All the pro components that need to be loaded
|
17
|
+
COMPONENTS = %w[
|
18
|
+
base_consumer
|
19
|
+
performance_tracker
|
20
|
+
processing/scheduler
|
21
|
+
processing/jobs/consume_non_blocking
|
22
|
+
processing/jobs_builder
|
23
|
+
processing/coordinator
|
24
|
+
routing/extensions
|
25
|
+
active_job/consumer
|
26
|
+
active_job/dispatcher
|
27
|
+
active_job/job_options_contract
|
28
|
+
].freeze
|
29
|
+
|
30
|
+
private_constant :COMPONENTS
|
31
|
+
|
16
32
|
class << self
|
17
33
|
# Loads all the pro components and configures them wherever it is expected
|
18
34
|
# @param config [Dry::Configurable::Config] whole app config that we can alter with pro
|
19
35
|
# components
|
20
36
|
def setup(config)
|
21
|
-
require_relative
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
37
|
+
COMPONENTS.each { |component| require_relative(component) }
|
38
|
+
|
39
|
+
icfg = config.internal
|
40
|
+
|
41
|
+
icfg.processing.coordinator_class = Processing::Coordinator
|
42
|
+
icfg.processing.scheduler = Processing::Scheduler.new
|
43
|
+
icfg.processing.jobs_builder = Processing::JobsBuilder.new
|
44
|
+
|
45
|
+
icfg.active_job.consumer_class = ActiveJob::Consumer
|
46
|
+
icfg.active_job.dispatcher = ActiveJob::Dispatcher.new
|
47
|
+
icfg.active_job.job_options_contract = ActiveJob::JobOptionsContract.new
|
48
|
+
|
49
|
+
::Karafka::Routing::Topic.include(Routing::Extensions)
|
32
50
|
|
33
51
|
config.monitor.subscribe(PerformanceTracker.instance)
|
34
52
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
3
12
|
module Karafka
|
4
13
|
module Pro
|
5
|
-
# This Karafka component is a Pro component.
|
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
|
12
|
-
# of your code to Maciej Mensfeld.
|
13
|
-
|
14
14
|
# Tracker used to keep track of performance metrics
|
15
15
|
# It provides insights that can be used to optimize processing flow
|
16
16
|
class PerformanceTracker
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
module Pro
|
5
|
+
module Processing
|
6
|
+
# Pro coordinator that provides extra orchestration methods useful for parallel processing
|
7
|
+
# within the same partition
|
8
|
+
class Coordinator < ::Karafka::Processing::Coordinator
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -1,21 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
3
12
|
module Karafka
|
4
13
|
module Pro
|
5
14
|
# Pro components related to processing part of Karafka
|
6
15
|
module Processing
|
7
16
|
# Pro jobs
|
8
17
|
module Jobs
|
9
|
-
# This Karafka component is a Pro component.
|
10
|
-
# All of the commercial components are present in the lib/karafka/pro directory of this
|
11
|
-
# repository and their usage requires commercial license agreement.
|
12
|
-
#
|
13
|
-
# Karafka has also commercial-friendly license, commercial support and commercial
|
14
|
-
# components.
|
15
|
-
#
|
16
|
-
# By sending a pull request to the pro components, you are agreeing to transfer the
|
17
|
-
# copyright of your code to Maciej Mensfeld.
|
18
|
-
|
19
18
|
# The main job type in a non-blocking variant.
|
20
19
|
# This variant works "like" the regular consumption but pauses the partition for as long
|
21
20
|
# as it is needed until a job is done.
|
@@ -27,7 +26,7 @@ module Karafka
|
|
27
26
|
# management. This layer of the framework knows nothing about Kafka messages consumption.
|
28
27
|
class ConsumeNonBlocking < ::Karafka::Processing::Jobs::Consume
|
29
28
|
# Releases the blocking lock after it is done with the preparation phase for this job
|
30
|
-
def
|
29
|
+
def before_call
|
31
30
|
super
|
32
31
|
@non_blocking = true
|
33
32
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
12
|
+
module Karafka
|
13
|
+
module Pro
|
14
|
+
module Processing
|
15
|
+
# Pro jobs builder that supports lrj
|
16
|
+
class JobsBuilder < ::Karafka::Processing::JobsBuilder
|
17
|
+
# @param executor [Karafka::Processing::Executor]
|
18
|
+
# @param messages [Karafka::Messages::Messages] messages batch to be consumed
|
19
|
+
# @param coordinator [Karafka::Processing::Coordinator]
|
20
|
+
# @return [Karafka::Processing::Jobs::Consume] blocking job
|
21
|
+
# @return [Karafka::Pro::Processing::Jobs::ConsumeNonBlocking] non blocking for lrj
|
22
|
+
def consume(executor, messages, coordinator)
|
23
|
+
if executor.topic.long_running_job?
|
24
|
+
Jobs::ConsumeNonBlocking.new(executor, messages, coordinator)
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
12
|
+
module Karafka
|
13
|
+
module Pro
|
14
|
+
module Processing
|
15
|
+
# Optimizes scheduler that takes into consideration of execution time needed to process
|
16
|
+
# messages from given topics partitions. It uses the non-preemptive LJF algorithm
|
17
|
+
#
|
18
|
+
# This scheduler is designed to optimize execution times on jobs that perform IO operations
|
19
|
+
# as when taking IO into consideration, the can achieve optimized parallel processing.
|
20
|
+
#
|
21
|
+
# This scheduler can also work with virtual partitions.
|
22
|
+
#
|
23
|
+
# Aside from consumption jobs, other jobs do not run often, thus we can leave them with
|
24
|
+
# default FIFO scheduler from the default Karafka scheduler
|
25
|
+
class Scheduler < ::Karafka::Processing::Scheduler
|
26
|
+
# Schedules jobs in the LJF order for consumption
|
27
|
+
#
|
28
|
+
# @param queue [Karafka::Processing::JobsQueue] queue where we want to put the jobs
|
29
|
+
# @param jobs_array [Array<Karafka::Processing::Jobs::Base>] jobs we want to schedule
|
30
|
+
#
|
31
|
+
def schedule_consumption(queue, jobs_array)
|
32
|
+
pt = PerformanceTracker.instance
|
33
|
+
|
34
|
+
ordered = []
|
35
|
+
|
36
|
+
jobs_array.each do |job|
|
37
|
+
messages = job.messages
|
38
|
+
message = messages.first
|
39
|
+
|
40
|
+
cost = pt.processing_time_p95(message.topic, message.partition) * messages.size
|
41
|
+
|
42
|
+
ordered << [job, cost]
|
43
|
+
end
|
44
|
+
|
45
|
+
ordered.sort_by!(&:last)
|
46
|
+
ordered.reverse!
|
47
|
+
ordered.map!(&:first)
|
48
|
+
|
49
|
+
ordered.each do |job|
|
50
|
+
queue << job
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This Karafka component is a Pro component.
|
4
|
+
# All of the commercial components are present in the lib/karafka/pro directory of this
|
5
|
+
# repository and their usage requires commercial license agreement.
|
6
|
+
#
|
7
|
+
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
8
|
+
#
|
9
|
+
# By sending a pull request to the pro components, you are agreeing to transfer the copyright of
|
10
|
+
# your code to Maciej Mensfeld.
|
11
|
+
|
12
|
+
module Karafka
|
13
|
+
module Pro
|
14
|
+
# Pro routing components
|
15
|
+
module Routing
|
16
|
+
# Routing extensions that allow to configure some extra PRO routing options
|
17
|
+
module Extensions
|
18
|
+
class << self
|
19
|
+
# @param base [Class] class we extend
|
20
|
+
def included(base)
|
21
|
+
base.attr_accessor :long_running_job
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Boolean] is a given job on a topic a long running one
|
26
|
+
def long_running_job?
|
27
|
+
@long_running_job || false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|