defmodule Chaperon.Action.SpreadAsync do
@moduledoc """
Action that calls a function with a given `rate` over a given `interval` of
time (ms).
"""
defstruct func: nil,
rate: nil,
interval: nil,
task_name: nil
@type rate :: non_neg_integer
@type time :: non_neg_integer
@type t :: %__MODULE__{
func: Chaperon.CallFunction.callback(),
rate: rate,
interval: time,
task_name: atom
}
end
defimpl Chaperon.Actionable, for: Chaperon.Action.SpreadAsync do
alias Chaperon.Session
use Chaperon.Session.Logging
def run(action, session) do
delay = round(action.interval / action.rate)
session
|> log_info("SpreadAsync[#{action.rate} / #{action.interval} @ #{delay}]")
1..action.rate
|> Enum.map(fn _ ->
action
|> execute_task(session, delay)
end)
|> Enum.reduce(session, fn task, session ->
session
|> Session.add_async_task(action.func, task)
end)
|> Session.ok()
end
defp execute_task(action, session, delay) do
session =
session
|> Session.delay(delay)
|> Session.fork()
Chaperon.Worker.Supervisor.schedule_async(fn ->
session
|> Session.time(action.func, fn session ->
apply(session.scenario.module, action.func, [session])
end)
end)
end
def abort(action, session) do
# TODO
{:ok, action, session}
end
end
defimpl String.Chars, for: Chaperon.Action.SpreadAsync do
def to_string(%{func: func, rate: r, interval: i}) when is_atom(func) do
"SpreadAsync[#{func}, #{r}, #{i}]"
end
def to_string(%{func: func, rate: r, interval: i}) when is_function(func) do
"SpreadAsync[#{inspect(func)}, #{r}, #{i}]"
end
end