Current section

Files

Jump to
strom lib gen_mix tasks.ex
Raw

lib/gen_mix/tasks.ex

defmodule Strom.GenMix.Tasks do
@moduledoc "Utility module. There are fucntions for manipulating tasks in gen_mix"
alias Strom.GenMix
alias Strom.Composite
def start_tasks(input_streams, %GenMix{} = gm) do
Enum.reduce(input_streams, %{}, fn {name, stream}, acc ->
task_pid =
run_stream_in_task(
{name, stream},
{gm.pid, gm.outputs, gm.chunk},
gm.process_chunk,
gm.composite
)
Map.put(acc, task_pid, name)
end)
end
def run_tasks(tasks, accs) do
Enum.each(tasks, fn {task_pid, name} ->
send(task_pid, {:task, :run, accs[name]})
end)
tasks
end
def handle_task_error(%GenMix{} = gm, pid) do
{_, name} = Enum.find(gm.tasks, fn {task_pid, _name} -> task_pid == pid end)
stream = Map.get(gm.input_streams, name)
task_pid =
run_stream_in_task(
{name, stream},
{gm.pid, gm.outputs, gm.chunk},
gm.process_chunk,
gm.composite
)
send(task_pid, {:task, :run, gm.accs[name]})
{task_pid, name}
end
def terminate_tasks(tasks) do
Enum.each(
Map.keys(tasks),
&DynamicSupervisor.terminate_child(Strom.TaskSupervisor, &1)
)
end
defp run_stream_in_task({name, stream}, {gm_identifier, outputs, chunk}, process_chunk, nil) do
task =
Task.Supervisor.async_nolink(
{:via, PartitionSupervisor, {Strom.TaskSupervisor, self()}},
task_function({name, stream}, {gm_identifier, outputs, chunk}, process_chunk)
)
task.pid
end
defp run_stream_in_task(
{name, stream},
{gm_identifier, outputs, chunk},
process_chunk,
composite_name
) do
supervisor_name = Composite.task_supervisor_name(composite_name)
{:ok, task_pid} =
DynamicSupervisor.start_child(
supervisor_name,
%{
id: Task,
start:
{Task, :start_link,
[task_function({name, stream}, {gm_identifier, outputs, chunk}, process_chunk)]},
restart: :temporary
}
)
Process.unlink(task_pid)
Process.monitor(task_pid)
task_pid
end
defp task_function({name, stream}, {gm_pid, outputs, chunk}, process_chunk) do
fn ->
acc =
receive do
{:task, :run, acc} ->
acc
end
stream
|> Stream.chunk_every(chunk)
|> Stream.transform(
fn -> {gm_pid, acc} end,
fn chunk, {gm_pid, acc} ->
case process_chunk.(name, chunk, outputs, acc) do
{new_data, true, new_acc} ->
GenServer.cast(gm_pid, {:put_data, {name, self()}, {new_data, new_acc}})
receive do
{:task, :run, _acc} ->
# ignore the message
{[], {gm_pid, new_acc}}
{:task, :run_new_tasks_and_halt, {task_pid, acc}} ->
send(task_pid, {:task, :run, acc})
{:halt, {gm_pid, new_acc}}
{:task, ^name, :continue} ->
{[], {gm_pid, new_acc}}
{:task, :halt} ->
{:halt, {gm_pid, new_acc}}
end
{_new_data, false, new_acc} ->
{[], {gm_pid, new_acc}}
end
end,
fn {gm_pid, acc} -> {gm_pid, acc} end
)
|> Stream.run()
self()
end
end
end