A use case is either a module that exports a unary exec/1 function, or any
unary function (an fn closure or a &Module.function/1 capture).
Interact.UseCase wraps either form in a struct and provides a pipeline for
controlling execution.
Pipeline
import Interact.UseCase
create(MyApp.MyUseCase) # fully-qualified module, or a unary function
|> async() # fire and forget; default is synchronous (optional)
|> timeout(ms) # kill the task after ms milliseconds (optional)
|> callback(functions) # called with the result struct after completion (optional)
|> reply(pids) # processes to receive the result struct (optional)
|> input(data) # input passed to exec/1
|> run() # execute the use caserun/2 is a shorthand for input/2 |> run/1. Every pipeline function
accepts a module or function directly and calls create/1 automatically,
so the pipeline can start at any step — create/1 is never required.
The struct is single-use: once run/1 is called the use case is considered
started, and any further pipeline call — including run/1 itself — raises
ArgumentError.
Result struct
The %Interact.UseCase{} returned by run/1 always reflects the full
execution:
output— return value ofexec/1, ornilon errorerror— exception struct ifexec/1raised,nilon successstacktrace— stacktrace whenerroris an exception,nilotherwisestarted_at,finished_at—DateTimeUTC timestampstimedout_at—DateTimeUTC timestamp set when the deadline was exceeded,nilotherwise
Callbacks and replies fire even on failure, so result handling is uniform regardless of outcome.
Summary
Types
@type t(i, o) :: %Interact.UseCase{ async: boolean(), callbacks: [(t(i, o) -> any())], error: Exception.t() | nil, finished_at: DateTime.t() | nil, input: i | nil, logic: atom() | (i -> o), output: o | nil, reply: [pid()], stacktrace: Exception.stacktrace() | nil, started_at: DateTime.t() | nil, timedout_at: DateTime.t() | nil, timeout: timeout() }