Packages

Aerospike driver for Elixir with an OTP-native cluster runtime

Current section

Files

Jump to
aerospike_driver lib aerospike runtime async_task.ex
Raw

lib/aerospike/runtime/async_task.ex

defmodule Aerospike.Runtime.AsyncTask do
@moduledoc false
@doc """
Blocks until the async operation completes or the timeout is exceeded.
"""
@callback wait(struct(), keyword()) :: :ok | {:error, Aerospike.Error.t()}
@doc """
Returns the current status of the async operation.
"""
@callback status(struct()) :: {:ok, :complete | :in_progress} | {:error, Aerospike.Error.t()}
@doc false
defmacro __using__(_opts) do
quote do
alias Aerospike.Runtime.AsyncTask
@behaviour AsyncTask
@impl AsyncTask
@doc """
Blocks until the async operation completes or the timeout is exceeded.
Supported options:
* `:poll_interval` — milliseconds to sleep between status checks.
Defaults to `1_000`.
* `:timeout` — maximum milliseconds to wait. When omitted, polling
continues until the operation completes or returns an error.
"""
@spec wait(struct()) :: :ok | {:error, Aerospike.Error.t()}
@spec wait(struct(), keyword()) :: :ok | {:error, Aerospike.Error.t()}
def wait(task, opts \\ []) do
AsyncTask.poll(__MODULE__, task, opts)
end
defoverridable wait: 2
end
end
@doc false
def poll(module, task, opts) do
poll_interval = Keyword.get(opts, :poll_interval, 1_000)
timeout_ms = Keyword.get(opts, :timeout, nil)
deadline = if timeout_ms, do: System.monotonic_time(:millisecond) + timeout_ms, else: nil
do_poll(module, task, poll_interval, deadline)
end
defp do_poll(module, task, poll_interval, deadline) do
case module.status(task) do
{:ok, :complete} ->
:ok
{:ok, :in_progress} ->
if deadline && System.monotonic_time(:millisecond) >= deadline do
{:error, Aerospike.Error.from_result_code(:timeout)}
else
Process.sleep(poll_interval)
do_poll(module, task, poll_interval, deadline)
end
{:error, _} = error ->
error
end
end
end