karafka 1.2.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coditsu.yml +3 -0
- data/.console_irbrc +13 -0
- data/.gitignore +68 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +49 -0
- data/CHANGELOG.md +458 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/CONTRIBUTING.md +41 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +126 -0
- data/MIT-LICENCE +18 -0
- data/README.md +102 -0
- data/bin/karafka +19 -0
- data/config/errors.yml +6 -0
- data/karafka.gemspec +42 -0
- data/lib/karafka.rb +79 -0
- data/lib/karafka/app.rb +45 -0
- data/lib/karafka/attributes_map.rb +69 -0
- data/lib/karafka/backends/inline.rb +16 -0
- data/lib/karafka/base_consumer.rb +68 -0
- data/lib/karafka/base_responder.rb +208 -0
- data/lib/karafka/callbacks.rb +30 -0
- data/lib/karafka/callbacks/config.rb +22 -0
- data/lib/karafka/callbacks/dsl.rb +16 -0
- data/lib/karafka/cli.rb +54 -0
- data/lib/karafka/cli/base.rb +78 -0
- data/lib/karafka/cli/console.rb +29 -0
- data/lib/karafka/cli/flow.rb +46 -0
- data/lib/karafka/cli/info.rb +29 -0
- data/lib/karafka/cli/install.rb +42 -0
- data/lib/karafka/cli/server.rb +66 -0
- data/lib/karafka/connection/api_adapter.rb +148 -0
- data/lib/karafka/connection/builder.rb +16 -0
- data/lib/karafka/connection/client.rb +107 -0
- data/lib/karafka/connection/delegator.rb +46 -0
- data/lib/karafka/connection/listener.rb +60 -0
- data/lib/karafka/consumers/callbacks.rb +54 -0
- data/lib/karafka/consumers/includer.rb +51 -0
- data/lib/karafka/consumers/responders.rb +24 -0
- data/lib/karafka/consumers/single_params.rb +15 -0
- data/lib/karafka/errors.rb +50 -0
- data/lib/karafka/fetcher.rb +44 -0
- data/lib/karafka/helpers/class_matcher.rb +78 -0
- data/lib/karafka/helpers/config_retriever.rb +46 -0
- data/lib/karafka/helpers/multi_delegator.rb +33 -0
- data/lib/karafka/instrumentation/listener.rb +112 -0
- data/lib/karafka/instrumentation/logger.rb +55 -0
- data/lib/karafka/instrumentation/monitor.rb +64 -0
- data/lib/karafka/loader.rb +28 -0
- data/lib/karafka/params/dsl.rb +158 -0
- data/lib/karafka/params/params_batch.rb +46 -0
- data/lib/karafka/parsers/json.rb +38 -0
- data/lib/karafka/patches/dry_configurable.rb +33 -0
- data/lib/karafka/patches/ruby_kafka.rb +34 -0
- data/lib/karafka/persistence/client.rb +25 -0
- data/lib/karafka/persistence/consumer.rb +38 -0
- data/lib/karafka/persistence/topic.rb +29 -0
- data/lib/karafka/process.rb +62 -0
- data/lib/karafka/responders/builder.rb +36 -0
- data/lib/karafka/responders/topic.rb +57 -0
- data/lib/karafka/routing/builder.rb +61 -0
- data/lib/karafka/routing/consumer_group.rb +61 -0
- data/lib/karafka/routing/consumer_mapper.rb +34 -0
- data/lib/karafka/routing/proxy.rb +37 -0
- data/lib/karafka/routing/router.rb +29 -0
- data/lib/karafka/routing/topic.rb +60 -0
- data/lib/karafka/routing/topic_mapper.rb +55 -0
- data/lib/karafka/schemas/config.rb +24 -0
- data/lib/karafka/schemas/consumer_group.rb +78 -0
- data/lib/karafka/schemas/consumer_group_topic.rb +18 -0
- data/lib/karafka/schemas/responder_usage.rb +39 -0
- data/lib/karafka/schemas/server_cli_options.rb +43 -0
- data/lib/karafka/server.rb +85 -0
- data/lib/karafka/setup/config.rb +193 -0
- data/lib/karafka/setup/configurators/base.rb +29 -0
- data/lib/karafka/setup/configurators/params.rb +25 -0
- data/lib/karafka/setup/configurators/water_drop.rb +32 -0
- data/lib/karafka/setup/dsl.rb +22 -0
- data/lib/karafka/status.rb +25 -0
- data/lib/karafka/templates/application_consumer.rb.example +6 -0
- data/lib/karafka/templates/application_responder.rb.example +11 -0
- data/lib/karafka/templates/karafka.rb.example +54 -0
- data/lib/karafka/version.rb +7 -0
- data/log/.gitkeep +0 -0
- metadata +303 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
module Callbacks
|
5
|
+
# App level dsl to define callbacks
|
6
|
+
module Dsl
|
7
|
+
Callbacks::TYPES.each do |callback_type|
|
8
|
+
# Allows us to define a block, that will be executed for a given moment
|
9
|
+
# @param [Block] block that should be executed after the initialization process
|
10
|
+
define_method callback_type do |&block|
|
11
|
+
config.callbacks.send(callback_type).push block
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/karafka/cli.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
# Karafka framework Cli
|
5
|
+
# If you want to add/modify command that belongs to CLI, please review all commands
|
6
|
+
# available in cli/ directory inside Karafka source code.
|
7
|
+
#
|
8
|
+
# @note Whole Cli is built using Thor
|
9
|
+
# @see https://github.com/erikhuda/thor
|
10
|
+
class Cli < Thor
|
11
|
+
package_name 'Karafka'
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# Loads all Cli commands into Thor framework
|
15
|
+
# This method should be executed before we run Karafka::Cli.start, otherwise we won't
|
16
|
+
# have any Cli commands available
|
17
|
+
def prepare
|
18
|
+
cli_commands.each do |action|
|
19
|
+
action.bind_to(self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# @return [Array<Class>] Array with Cli action classes that can be used as commands
|
26
|
+
def cli_commands
|
27
|
+
constants
|
28
|
+
.map! { |object| const_get(object) }
|
29
|
+
.keep_if do |object|
|
30
|
+
object.instance_of?(Class) && (object < Cli::Base)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# This is kinda trick - since we don't have a autoload and other magic stuff
|
38
|
+
# like Rails does, so instead this method allows us to replace currently running
|
39
|
+
# console with a new one via Kernel.exec. It will start console with new code loaded
|
40
|
+
# Yes we know that it is not turbofast, however it is turbo convinient and small
|
41
|
+
#
|
42
|
+
# Also - the KARAFKA_CONSOLE is used to detect that we're executing the irb session
|
43
|
+
# so this method is only available when the Karafka console is running
|
44
|
+
#
|
45
|
+
# We skip this because this should exist and be only valid in the console
|
46
|
+
# :nocov:
|
47
|
+
if ENV['KARAFKA_CONSOLE']
|
48
|
+
# Reloads Karafka irb console session
|
49
|
+
def reload!
|
50
|
+
puts "Reloading...\n"
|
51
|
+
Kernel.exec Karafka::Cli::Console.command
|
52
|
+
end
|
53
|
+
end
|
54
|
+
# :nocov:
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
class Cli < Thor
|
5
|
+
# Base class for all the command that we want to define
|
6
|
+
# This base class provides a nicer interface to Thor and allows to easier separate single
|
7
|
+
# independent commands
|
8
|
+
# In order to define a new command you need to:
|
9
|
+
# - specify its desc
|
10
|
+
# - implement call method
|
11
|
+
#
|
12
|
+
# @example Create a dummy command
|
13
|
+
# class Dummy < Base
|
14
|
+
# self.desc = 'Dummy command'
|
15
|
+
#
|
16
|
+
# def call
|
17
|
+
# puts 'I'm doing nothing!
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
class Base
|
21
|
+
include Thor::Shell
|
22
|
+
|
23
|
+
# We can use it to call other cli methods via this object
|
24
|
+
attr_reader :cli
|
25
|
+
|
26
|
+
# @param cli [Karafka::Cli] current Karafka Cli instance
|
27
|
+
def initialize(cli)
|
28
|
+
@cli = cli
|
29
|
+
end
|
30
|
+
|
31
|
+
# This method should implement proper cli action
|
32
|
+
def call
|
33
|
+
raise NotImplementedError, 'Implement this in a subclass'
|
34
|
+
end
|
35
|
+
|
36
|
+
class << self
|
37
|
+
# Allows to set options for Thor cli
|
38
|
+
# @see https://github.com/erikhuda/thor
|
39
|
+
# @param option Single option details
|
40
|
+
def option(*option)
|
41
|
+
@options ||= []
|
42
|
+
@options << option
|
43
|
+
end
|
44
|
+
|
45
|
+
# Allows to set description of a given cli command
|
46
|
+
# @param desc [String] Description of a given cli command
|
47
|
+
def desc(desc)
|
48
|
+
@desc ||= desc
|
49
|
+
end
|
50
|
+
|
51
|
+
# This method will bind a given Cli command into Karafka Cli
|
52
|
+
# This method is a wrapper to way Thor defines its commands
|
53
|
+
# @param cli_class [Karafka::Cli] Karafka cli_class
|
54
|
+
def bind_to(cli_class)
|
55
|
+
cli_class.desc name, @desc
|
56
|
+
|
57
|
+
(@options || []).each { |option| cli_class.option(*option) }
|
58
|
+
|
59
|
+
context = self
|
60
|
+
|
61
|
+
cli_class.send :define_method, name do |*args|
|
62
|
+
context.new(self).call(*args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# @return [String] downcased current class name that we use to define name for
|
69
|
+
# given Cli command
|
70
|
+
# @example for Karafka::Cli::Install
|
71
|
+
# name #=> 'install'
|
72
|
+
def name
|
73
|
+
to_s.split('::').last.downcase
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
# Karafka framework Cli
|
5
|
+
class Cli < Thor
|
6
|
+
# Console Karafka Cli action
|
7
|
+
class Console < Base
|
8
|
+
desc 'Start the Karafka console (short-cut alias: "c")'
|
9
|
+
option aliases: 'c'
|
10
|
+
|
11
|
+
# @return [String] Console executing command
|
12
|
+
# @example
|
13
|
+
# Karafka::Cli::Console.command #=> 'KARAFKA_CONSOLE=true bundle exec irb...'
|
14
|
+
def self.command
|
15
|
+
envs = [
|
16
|
+
"IRBRC='#{Karafka.gem_root}/.console_irbrc'",
|
17
|
+
'KARAFKA_CONSOLE=true'
|
18
|
+
]
|
19
|
+
"#{envs.join(' ')} bundle exec irb"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Start the Karafka console
|
23
|
+
def call
|
24
|
+
cli.info
|
25
|
+
exec self.class.command
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
# Karafka framework Cli
|
5
|
+
class Cli < Thor
|
6
|
+
# Description of topics flow (incoming/outgoing)
|
7
|
+
class Flow < Base
|
8
|
+
desc 'Print application data flow (incoming => outgoing)'
|
9
|
+
|
10
|
+
# Print out all defined routes in alphabetical order
|
11
|
+
def call
|
12
|
+
topics.each do |topic|
|
13
|
+
any_topics = !topic.responder&.topics.nil?
|
14
|
+
|
15
|
+
if any_topics
|
16
|
+
puts "#{topic.name} =>"
|
17
|
+
|
18
|
+
topic.responder.topics.each_value do |responder_topic|
|
19
|
+
features = []
|
20
|
+
features << (responder_topic.required? ? 'always' : 'conditionally')
|
21
|
+
features << (responder_topic.multiple_usage? ? 'one or more' : 'exactly once')
|
22
|
+
|
23
|
+
print responder_topic.name, "(#{features.join(', ')})"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
puts "#{topic.name} => (nothing)"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# @return [Array<Karafka::Routing::Topic>] all topics sorted in alphabetical order
|
34
|
+
def topics
|
35
|
+
Karafka::App.consumer_groups.map(&:topics).flatten.sort_by(&:name)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Prints a given value with label in a nice way
|
39
|
+
# @param label [String] label describing value
|
40
|
+
# @param value [String] value that should be printed
|
41
|
+
def print(label, value)
|
42
|
+
printf "%-25s %s\n", " - #{label}:", value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
# Karafka framework Cli
|
5
|
+
class Cli < Thor
|
6
|
+
# Info Karafka Cli action
|
7
|
+
class Info < Base
|
8
|
+
desc 'Print configuration details and other options of your application'
|
9
|
+
|
10
|
+
# Print configuration details and other options of your application
|
11
|
+
def call
|
12
|
+
config = Karafka::App.config
|
13
|
+
|
14
|
+
info = [
|
15
|
+
"Karafka framework version: #{Karafka::VERSION}",
|
16
|
+
"Application client id: #{config.client_id}",
|
17
|
+
"Backend: #{config.backend}",
|
18
|
+
"Batch fetching: #{config.batch_fetching}",
|
19
|
+
"Batch consuming: #{config.batch_consuming}",
|
20
|
+
"Boot file: #{Karafka.boot_file}",
|
21
|
+
"Environment: #{Karafka.env}",
|
22
|
+
"Kafka seed brokers: #{config.kafka.seed_brokers}"
|
23
|
+
]
|
24
|
+
|
25
|
+
puts(info.join("\n"))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
# Karafka framework Cli
|
5
|
+
class Cli < Thor
|
6
|
+
# Install Karafka Cli action
|
7
|
+
class Install < Base
|
8
|
+
desc 'Install all required things for Karafka application in current directory'
|
9
|
+
|
10
|
+
# Directories created by default
|
11
|
+
INSTALL_DIRS = %w[
|
12
|
+
app/consumers
|
13
|
+
app/responders
|
14
|
+
config
|
15
|
+
log
|
16
|
+
tmp/pids
|
17
|
+
].freeze
|
18
|
+
|
19
|
+
# Where should we map proper files from templates
|
20
|
+
INSTALL_FILES_MAP = {
|
21
|
+
'karafka.rb.example' => Karafka.boot_file.basename,
|
22
|
+
'application_consumer.rb.example' => 'app/consumers/application_consumer.rb',
|
23
|
+
'application_responder.rb.example' => 'app/responders/application_responder.rb'
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
# Install all required things for Karafka application in current directory
|
27
|
+
def call
|
28
|
+
INSTALL_DIRS.each do |dir|
|
29
|
+
FileUtils.mkdir_p Karafka.root.join(dir)
|
30
|
+
end
|
31
|
+
|
32
|
+
INSTALL_FILES_MAP.each do |source, target|
|
33
|
+
target = Karafka.root.join(target)
|
34
|
+
next if File.exist?(target)
|
35
|
+
|
36
|
+
source = Karafka.core_root.join("templates/#{source}")
|
37
|
+
FileUtils.cp_r(source, target)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
# Karafka framework Cli
|
5
|
+
class Cli < Thor
|
6
|
+
# Server Karafka Cli action
|
7
|
+
class Server < Base
|
8
|
+
desc 'Start the Karafka server (short-cut alias: "s")'
|
9
|
+
option aliases: 's'
|
10
|
+
option :daemon, default: false, type: :boolean, aliases: :d
|
11
|
+
option :pid, default: 'tmp/pids/karafka', type: :string, aliases: :p
|
12
|
+
option :consumer_groups, type: :array, default: nil, aliases: :g
|
13
|
+
|
14
|
+
# Start the Karafka server
|
15
|
+
def call
|
16
|
+
validate!
|
17
|
+
|
18
|
+
puts 'Starting Karafka server'
|
19
|
+
cli.info
|
20
|
+
|
21
|
+
if cli.options[:daemon]
|
22
|
+
FileUtils.mkdir_p File.dirname(cli.options[:pid])
|
23
|
+
daemonize
|
24
|
+
end
|
25
|
+
|
26
|
+
# We assign active topics on a server level, as only server is expected to listen on
|
27
|
+
# part of the topics
|
28
|
+
Karafka::Server.consumer_groups = cli.options[:consumer_groups]
|
29
|
+
|
30
|
+
# Remove pidfile on stop, just before the server instance is going to be GCed
|
31
|
+
# We want to delay the moment in which the pidfile is removed as much as we can,
|
32
|
+
# so instead of removing it after the server stops running, we rely on the gc moment
|
33
|
+
# when this object gets removed (it is a bit later), so it is closer to the actual
|
34
|
+
# system process end. We do that, so monitoring and deployment tools that rely on pids
|
35
|
+
# won't alarm or start new system process up until the current one is finished
|
36
|
+
ObjectSpace.define_finalizer(self, proc { send(:clean) })
|
37
|
+
|
38
|
+
Karafka::Server.run
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Checks the server cli configuration
|
44
|
+
# options validations in terms of app setup (topics, pid existence, etc)
|
45
|
+
def validate!
|
46
|
+
result = Schemas::ServerCliOptions.call(cli.options)
|
47
|
+
return if result.success?
|
48
|
+
raise Errors::InvalidConfiguration, result.errors
|
49
|
+
end
|
50
|
+
|
51
|
+
# Detaches current process into background and writes its pidfile
|
52
|
+
def daemonize
|
53
|
+
::Process.daemon(true)
|
54
|
+
File.open(
|
55
|
+
cli.options[:pid],
|
56
|
+
'w'
|
57
|
+
) { |file| file.write(::Process.pid) }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Removes a pidfile (if exist)
|
61
|
+
def clean
|
62
|
+
FileUtils.rm_f(cli.options[:pid]) if cli.options[:pid]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Karafka
|
4
|
+
# Namespace for all the things related to Kafka connection
|
5
|
+
module Connection
|
6
|
+
# Mapper used to convert our internal settings into ruby-kafka settings based on their
|
7
|
+
# API requirements.
|
8
|
+
# Since ruby-kafka has more and more options and there are few "levels" on which
|
9
|
+
# we have to apply them (despite the fact, that in Karafka you configure all of it
|
10
|
+
# in one place), we have to remap it into what ruby-kafka driver requires
|
11
|
+
# @note The good thing about Kafka.new method is that it ignores all options that
|
12
|
+
# do nothing. So we don't have to worry about injecting our internal settings
|
13
|
+
# into the client and breaking stuff
|
14
|
+
module ApiAdapter
|
15
|
+
class << self
|
16
|
+
# Builds all the configuration settings for Kafka.new method
|
17
|
+
# @return [Array<Hash>] Array with all the client arguments including hash with all
|
18
|
+
# the settings required by Kafka.new method
|
19
|
+
# @note We return array, so we can inject any arguments we want, in case of changes in the
|
20
|
+
# raw driver
|
21
|
+
def client
|
22
|
+
# This one is a default that takes all the settings except special
|
23
|
+
# cases defined in the map
|
24
|
+
settings = {
|
25
|
+
logger: ::Karafka.logger,
|
26
|
+
client_id: ::Karafka::App.config.client_id
|
27
|
+
}
|
28
|
+
|
29
|
+
kafka_configs.each do |setting_name, setting_value|
|
30
|
+
# All options for config adapter should be ignored as we're just interested
|
31
|
+
# in what is left, as we want to pass all the options that are "typical"
|
32
|
+
# and not listed in the api_adapter special cases mapping. All the values
|
33
|
+
# from the api_adapter mapping go somewhere else, not to the client directly
|
34
|
+
next if AttributesMap.api_adapter.values.flatten.include?(setting_name)
|
35
|
+
|
36
|
+
settings[setting_name] = setting_value
|
37
|
+
end
|
38
|
+
|
39
|
+
settings_hash = sanitize(settings)
|
40
|
+
|
41
|
+
# Normalization for the way Kafka::Client accepts arguments from 0.5.3
|
42
|
+
[settings_hash.delete(:seed_brokers), settings_hash]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Builds all the configuration settings for kafka#consumer method
|
46
|
+
# @param consumer_group [Karafka::Routing::ConsumerGroup] consumer group details
|
47
|
+
# @return [Array<Hash>] array with all the consumer arguments including hash with all
|
48
|
+
# the settings required by Kafka#consumer
|
49
|
+
def consumer(consumer_group)
|
50
|
+
settings = { group_id: consumer_group.id }
|
51
|
+
settings = fetch_for(:consumer, consumer_group, settings)
|
52
|
+
[sanitize(settings)]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Builds all the configuration settings for kafka consumer consume_each_batch and
|
56
|
+
# consume_each_message methods
|
57
|
+
# @param consumer_group [Karafka::Routing::ConsumerGroup] consumer group details
|
58
|
+
# @return [Array<Hash>] Array with all the arguments required by consuming method
|
59
|
+
# including hash with all the settings required by
|
60
|
+
# Kafka::Consumer#consume_each_message and Kafka::Consumer#consume_each_batch method
|
61
|
+
def consumption(consumer_group)
|
62
|
+
[
|
63
|
+
sanitize(
|
64
|
+
fetch_for(
|
65
|
+
:consumption,
|
66
|
+
consumer_group,
|
67
|
+
automatically_mark_as_processed: consumer_group.automatically_mark_as_consumed
|
68
|
+
)
|
69
|
+
)
|
70
|
+
]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Builds all the configuration settings for kafka consumer#subscribe method
|
74
|
+
# @param topic [Karafka::Routing::Topic] topic that holds details for a given subscription
|
75
|
+
# @return [Hash] hash with all the settings required by kafka consumer#subscribe method
|
76
|
+
def subscribe(topic)
|
77
|
+
settings = fetch_for(:subscribe, topic)
|
78
|
+
[Karafka::App.config.topic_mapper.outgoing(topic.name), sanitize(settings)]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Builds all the configuration settings required by kafka consumer#pause method
|
82
|
+
# @param topic [String] topic that we want to pause
|
83
|
+
# @param partition [Integer] number partition that we want to pause
|
84
|
+
# @param consumer_group [Karafka::Routing::ConsumerGroup] consumer group details
|
85
|
+
# @return [Array] array with all the details required to pause kafka consumer
|
86
|
+
def pause(topic, partition, consumer_group)
|
87
|
+
[
|
88
|
+
Karafka::App.config.topic_mapper.outgoing(topic),
|
89
|
+
partition,
|
90
|
+
{ timeout: consumer_group.pause_timeout }
|
91
|
+
]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Remaps topic details taking the topic mapper feature into consideration.
|
95
|
+
# @param params [Karafka::Params::Params] params instance
|
96
|
+
# @return [Array] array with all the details needed by ruby-kafka to mark message
|
97
|
+
# as processed
|
98
|
+
# @note When default empty topic mapper is used, no need for any conversion as the
|
99
|
+
# internal and external format are exactly the same
|
100
|
+
def mark_message_as_processed(params)
|
101
|
+
# Majority of non heroku users don't use custom topic mappers. No need to change
|
102
|
+
# anything when it is a default mapper that does not change anything
|
103
|
+
return [params] if Karafka::App.config.topic_mapper == Karafka::Routing::TopicMapper
|
104
|
+
|
105
|
+
# @note We don't use tap as it is around 13% slower than non-dup version
|
106
|
+
dupped = params.dup
|
107
|
+
dupped['topic'] = Karafka::App.config.topic_mapper.outgoing(params.topic)
|
108
|
+
[dupped]
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
# Fetches proper settings for a given map namespace
|
114
|
+
# @param namespace_key [Symbol] namespace from attributes map config adapter hash
|
115
|
+
# @param route_layer [Object] route topic or consumer group
|
116
|
+
# @param preexisting_settings [Hash] hash with some preexisting settings that might have
|
117
|
+
# been loaded in a different way
|
118
|
+
def fetch_for(namespace_key, route_layer, preexisting_settings = {})
|
119
|
+
kafka_configs.each_key do |setting_name|
|
120
|
+
# Ignore settings that are not related to our namespace
|
121
|
+
next unless AttributesMap.api_adapter[namespace_key].include?(setting_name)
|
122
|
+
# Ignore settings that are already initialized
|
123
|
+
# In case they are in preexisting settings fetched differently
|
124
|
+
next if preexisting_settings.key?(setting_name)
|
125
|
+
# Fetch all the settings from a given layer object. Objects can handle the fallback
|
126
|
+
# to the kafka settings, so
|
127
|
+
preexisting_settings[setting_name] = route_layer.send(setting_name)
|
128
|
+
end
|
129
|
+
|
130
|
+
preexisting_settings
|
131
|
+
end
|
132
|
+
|
133
|
+
# Removes nil containing keys from the final settings so it can use Kafkas driver
|
134
|
+
# defaults for those
|
135
|
+
# @param settings [Hash] settings that may contain nil values
|
136
|
+
# @return [Hash] settings without nil using keys (non of karafka options should be nil)
|
137
|
+
def sanitize(settings)
|
138
|
+
settings.reject { |_key, value| value.nil? }
|
139
|
+
end
|
140
|
+
|
141
|
+
# @return [Hash] Kafka config details as a hash
|
142
|
+
def kafka_configs
|
143
|
+
::Karafka::App.config.kafka.to_h
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|