Current section
Files
Jump to
Current section
Files
src/framework/kflow.erl
%%%===================================================================
%%% @copyright 2019 Klarna Bank AB (publ)
%%%
%%% @doc This module contains operation and maintenance functions.
%%%
%%% @end
%%%===================================================================
-module(kflow).
-include("kflow_int.hrl").
%% API exports
-export([ mk_kafka_workflow/3
, kafka_client_settings/1
, kafka_client_settings/0
]).
-export_type([ message/0
, node_id/0
, node_spec/1
, node_spec/0
, node_config/0
, behavior/0
, offset/0
, pipe/0
, workflow/0
, kafka_config/0
]).
%%====================================================================
%% Types
%%====================================================================
-type message() :: #kflow_msg{}.
-type node_id() :: [atom()].
-type offset() :: integer().
-type behavior() :: atom().
-type route() :: list().
-type node_config() :: #{ hard_timeout => timeout()
, max_queue_len => non_neg_integer()
}.
-type node_spec(CallbackConfig) ::
{ Behavior :: behavior()
, CallbackModule :: module()
, CallbackConfig
}
| { Behavior :: behavior()
, NodeConfig :: node_config()
, CallbackModule :: module()
, CallbackConfig
}
| {map, kflow_gen_map:callback_fun()}
| {filter, kflow_gen_filter:callback_fun()}
| {demux, kflow_gen_demux:callback_fun()}
| {mfd, kflow_gen_mfd:callback_fun()}
| {unfold, kflow_gen_unfold:callback_fun()}
| {route_dependent, kflow_route_dependent:callback_fun()}
| join
.
-type node_spec() :: node_spec(_).
-type pipe() :: [node_spec(), ...].
-type workflow() ::
#{ start := {module(), atom()}
, args := #{id := atom(), _ => _}
, _ => _ %% TODO: Remove after migration to new brod behavior
}.
-type kafka_config() ::
#{ kafka_topic := binary()
, group_id := binary()
, kafka_client => atom()
, consumer_config => brod:consumer_config()
, _ => _
}.
%%====================================================================
%% API functions
%%====================================================================
%% @doc Helper function for creating standard Kafka workflows
-spec mk_kafka_workflow(atom(), pipe(), kafka_config()) -> workflow().
mk_kafka_workflow(Id, PipeSpec, Config) ->
#{ kafka_topic := Topic
, group_id := GroupId
} = Config,
Client = maps:get(kafka_client, Config, ?default_brod_client),
Args = (maps:with([feed_timeout, shutdown_timeout, flush_interval, auto_commit], Config))
#{ group_id => GroupId
, topics => [Topic]
, id => Id
, pipe_spec => PipeSpec
, consumer_config => maps:get(consumer_config, Config, [])
, brod_client_id => Client
},
#{ start => {kflow_kafka_consumer_v2, start_link}
, args => Args
}.
%% @doc Get Kafka connection setting of the default client
-spec kafka_client_settings() ->
{[brod:endpoint()], brod:client_config()}.
kafka_client_settings() ->
kafka_client_settings(?default_brod_client).
%% @doc Get Kafka connection settings
-spec kafka_client_settings(atom()) ->
{[brod:endpoint()], brod:client_config()}.
kafka_client_settings(Name) ->
Endpoints = kafka_config(Name, kafka_endpoints),
ReqTimeout = kafka_config(Name, kafka_request_timeout),
SSL = kafka_config(Name, kafka_ssl),
SASL = kafka_config(Name, kafka_sasl),
DefaultProducerConfig = [{compression, gzip}],
ClientConfig0 = [ {allow_topic_auto_creation, false}
, {compression, gzip}
, {request_timeout, ReqTimeout}
, {auto_start_producers, true}
, {default_producer_config, DefaultProducerConfig}
, {ssl, SSL}
],
{Endpoints,
case SASL of
true ->
SaslFile = kafka_config(Name, kafka_sasl_file),
ClientConfig0 ++ [{sasl, {plain, SaslFile}}];
false ->
ClientConfig0
end}.
%%====================================================================
%% Internal functions
%%====================================================================
%% @private Try to find configuration key of brod client, and fallback
%% to the default value.
-spec kafka_config(atom(), atom()) -> term().
kafka_config(ClientName, Key) ->
case ?cfg(kafka_clients) of
#{ClientName := #{Key := Override}} ->
Override;
_ ->
?cfg(Key)
end.