Packages
SuperWorker is a powerful Elixir library for working with supervisors and background jobs. It provides a much simpler approach than traditional supervisors. This library is currently under development and is unstable, so it is not recommended for production use.
Current section
Files
Jump to
Current section
Files
lib/supervisor/api_helper.ex
defmodule SuperWorker.Supervisor.ApiHelper do
@moduledoc """
Utility functions for SuperWorker.Supervisor.
This module provides common utility functions used across the supervisor
implementation, including:
- API call helpers
"""
@type api_result :: {:ok, any()} | {:error, any()}
@type timeout_ms :: non_neg_integer() | :infinity
# List message from api.
@api_types [
:start_worker,
:remove_group_worker,
:send_to_group,
:send_to_group_random,
:add_data_to_chain,
:send_to_standalone_worker,
:count_workers_in_group,
:add_group,
:add_chain,
:stop_supervisor
]
alias SuperWorker.Supervisor.Message
require Logger
require SuperWorker.Log
# ============================================================================
# API Communication Helpers
# ============================================================================
@doc """
Waits for an API response matching the given reference.
Blocks until a message with the matching reference is received
or the timeout expires.
## Examples
# ... send message with ref ...
api_receiver(ref, 5000)
"""
@spec api_receiver(reference(), timeout_ms()) :: any()
def api_receiver(ref, timeout) when is_reference(ref) do
receive do
{^ref, result} -> result
after
timeout -> {:error, :api_timeout}
end
end
@doc """
Sends an API response to the caller.
## Examples
def handle_api({from, ref}, params) do
result = do_work(params)
api_response({from, ref}, result)
end
"""
@spec api_response(Message.t(), any()) :: any()
def api_response(message = %Message{}, result) do
send(message.from, {message.id, result})
end
@doc """
Makes a synchronous API call to a target process.
Sends a message in the format `{api_name, {from, ref}, params}` and waits
for a response with the matching reference.
## Parameters
- `target` - The pid or registered name of the target process
- `api` - The API function name (atom)
- `params` - Parameters to pass to the API
- `timeout` - Maximum time to wait for response in milliseconds
## Examples
result = call_api(:my_supervisor, :get_worker, worker_id, 5000)
"""
@spec call_api(atom() | pid(), atom(), any(), timeout_ms()) :: any()
def call_api(target, api, params, timeout)
when (is_atom(target) or is_pid(target)) and is_atom(api) do
SuperWorker.Log.debug(fn ->
"SuperWorker, Utils, call API: #{inspect(api)}, params: #{inspect(params)}, target: #{inspect(target)}"
end)
message = Message.new(api, target, params)
send(target, {:public_api, message})
api_receiver(message.id, timeout)
end
@doc """
Makes an asynchronous API call (fire-and-forget).
Sends a message but does not wait for a response.
## Examples
call_api_no_reply(:my_supervisor, :notify, :data_updated)
"""
@spec call_api_no_reply(atom() | pid(), atom(), any()) :: reference()
def call_api_no_reply(target, api, params)
when (is_atom(target) or is_pid(target)) and is_atom(api) do
message =
Message.new(api, target, params)
|> Map.put(:from, nil)
send(message.to, {:public_api, message})
message.id
end
@spec internal_call_api_no_reply(atom() | pid(), atom(), any()) :: reference()
def internal_call_api_no_reply(target, api, params)
when (is_atom(target) or is_pid(target)) and is_atom(api) do
message =
Message.new(api, target, params)
|> Map.put(:from, nil)
send(message.to, {:internal_api, message})
message.id
end
def valid_type?(type), do: type in @api_types
end