Current section

Files

Jump to
klife lib klife.ex
Raw

lib/klife.ex

defmodule Klife do
@moduledoc """
Main functions to interact with clients.
Usually you will not need to call any function here directly
but instead use them through a module that uses `Klife.Client`.
"""
alias Klife.Record
alias Klife.Producer
alias Klife.TxnProducerPool
alias Klife.Producer.Controller, as: PController
alias Klife.Connection.Controller, as: ConnController
@produce_opts [
producer: [
type: :atom,
required: false,
doc:
"Producer's name that will override the `default_producer` configuration. Ignored inside transactions."
],
partitioner: [
type: :atom,
required: false,
doc: "Module that will override `default_partitioner` configuration."
]
]
@async_opts [
callback: [
type: :any,
required: false,
doc:
"MFA or function/1 that will be called with the produce result. The result is injected as the first argument on MFA and is the only argument for anonymous functions"
]
]
@txn_opts [
pool_name: [
type: :atom,
required: false,
doc: "Txn pool's name that will override the `default_txn_pool` configuration."
]
]
@doc false
def get_produce_opts(), do: @produce_opts
@doc false
def get_txn_opts(), do: @txn_opts
@doc false
def get_async_opts(), do: @async_opts
@doc false
def produce(%Record{} = record, client, opts \\ []) do
[resp] = produce_batch([record], client, opts)
resp
end
@doc false
def produce_batch([%Record{} | _] = records, client, opts \\ []) do
records = prepare_records(records, client, opts)
if TxnProducerPool.in_txn?(client) do
TxnProducerPool.produce(records, client, opts)
else
if ConnController.disabled_feature?(client, :producer) do
raise """
You have tried to call the Produce API, but the producer feature is disabled. Check logs for details.
"""
end
Producer.produce(records, client, opts)
end
end
@doc false
def produce_async(%Record{} = record, client, opts \\ []) do
if ConnController.disabled_feature?(client, :producer) do
raise """
You have tried to call the Produce API, but the producer feature is disabled. Check logs for details.
"""
end
prepared_rec = prepare_records(record, client, opts)
Producer.produce_async([prepared_rec], client, opts)
end
@doc false
def produce_batch_async([%Record{} | _] = records, client, opts \\ []) do
if ConnController.disabled_feature?(client, :producer) do
raise """
You have tried to call the Produce API, but the producer feature is disabled. Check logs for details.
"""
end
case opts[:callback] do
nil ->
records = prepare_records(records, client, opts)
Producer.produce_async(records, client, opts)
{m, f, args} ->
Task.start(fn -> apply(m, f, [produce_batch(records, client, opts) | args]) end)
:ok
fun when is_function(fun, 1) ->
Task.start(fn -> fun.(produce_batch(records, client, opts)) end)
:ok
end
end
@doc false
def produce_batch_txn([%Record{} | _] = records, client, opts \\ []) do
transaction(
fn -> records |> produce_batch(client, opts) |> Record.verify_batch() end,
client,
opts
)
end
@doc false
def transaction(fun, client, opts \\ []) do
if ConnController.disabled_feature?(client, :txn_producer) do
raise """
You have tried to call the Transaction API, but the txn_producer feature is disabled. Check logs for details.
"""
end
TxnProducerPool.run_txn(client, get_txn_pool(client, opts), fun)
end
defp get_txn_pool(client, opts) do
Keyword.get(opts, :pool_name) || client.get_default_txn_pool()
end
defp maybe_add_partition(%Record{} = record, client, opts) do
case record do
%Record{partition: nil, topic: topic} ->
%{
default_partitioner: default_partitioner_mod,
max_partition: max_partition
} = PController.get_partitioner_data(client, topic)
partitioner_mod = Keyword.get(opts, :partitioner, default_partitioner_mod)
%{record | partition: partitioner_mod.get_partition(record, max_partition)}
record ->
record
end
end
defp prepare_records(%Record{} = rec, client, opts) do
[new_rec] = prepare_records([rec], client, opts)
new_rec
end
defp prepare_records(recs, client, opts) when is_list(recs) do
recs
|> Enum.with_index(1)
|> Enum.map(fn {rec, idx} ->
rec
|> Map.replace!(:__estimated_size, Record.estimate_size(rec))
|> Map.replace!(:__batch_index, idx)
|> maybe_add_partition(client, opts)
end)
end
end