View Source ExternalService (external_service v1.1.4)

ExternalService handles all retry and circuit breaker logic for calls to external services.

Link to this section Summary

Types

Union type representing all the possible error tuple return values

Error tuple returned when a fuse has been melted enough times that the fuse is blown

Name of a fuse

Error tuple returned when a fuse has not been initialized with ExternalService.start/1

Strategy controlling fuse behavior.

Options used for controlling circuit breaker and rate-limiting behavior.

A tuple specifying rate-limiting behavior.

Error tuple returned when the allowable number of retries has been exceeded

The sleep function to be called when reaching the configured rate limit quota.

Functions

Given a fuse name and retry options execute a function handling any retry and circuit breaker logic.

Like call/3, but raises an exception if retries are exhausted or the fuse is blown.

Asynchronous version of ExternalService.call.

Parallel, streaming version of ExternalService.call.

Parallel, streaming version of ExternalService.call.

Parallel, streaming version of ExternalService.call.

Resets the given fuse.

Initializes a new fuse for a specific service.

Stops the fuse for a specific service.

Link to this section Types

@type error() :: retries_exhausted() | fuse_blown() | fuse_not_found()

Union type representing all the possible error tuple return values

@type fuse_blown() :: {:error, {:fuse_blown, fuse_name()}}

Error tuple returned when a fuse has been melted enough times that the fuse is blown

@type fuse_name() :: term()

Name of a fuse

@type fuse_not_found() :: {:error, {:fuse_not_found, fuse_name()}}

Error tuple returned when a fuse has not been initialized with ExternalService.start/1

@type fuse_strategy() ::
  {:standard, max_melt_attempts :: pos_integer(), time_window :: pos_integer()}
  | {:fault_injection, rate :: float(), max_melt_attempts :: pos_integer(),
     time_window :: pos_integer()}

Strategy controlling fuse behavior.

@type options() :: [
  fuse_strategy: fuse_strategy(),
  fuse_refresh: pos_integer(),
  rate_limit: rate_limit(),
  sleep_function: sleep_function()
]

Options used for controlling circuit breaker and rate-limiting behavior.

See the fuse docs for further information about available fuse options.

@type rate_limit() :: {limit :: pos_integer(), time_window :: pos_integer()}

A tuple specifying rate-limiting behavior.

The first element of the tuple is the number of calls to allow in a given time window. The second element is the time window in milliseconds.

@type retriable_function() :: (-> retriable_function_result())
Link to this type

retriable_function_result()

View Source
@type retriable_function_result() ::
  :retry | {:retry, reason :: any()} | (function_result :: any())
@type retries_exhausted() :: {:error, {:retries_exhausted, reason :: any()}}

Error tuple returned when the allowable number of retries has been exceeded

@type sleep_function() :: (number() -> any())

The sleep function to be called when reaching the configured rate limit quota.

In some situations, like tests, blocking the process for an extended period of time can be undesired. In these cases this function can be changed. Defaults to Process.sleep/1.

Link to this section Functions

Link to this function

call(fuse_name, retry_opts \\ %RetryOptions{}, function)

View Source
@spec call(fuse_name(), ExternalService.RetryOptions.t(), retriable_function()) ::
  error() | (function_result :: any())

Given a fuse name and retry options execute a function handling any retry and circuit breaker logic.

ExternalService.start must be run with the fuse name before using call.

The provided function can indicate that a retry should be performed by returning the atom :retry or a tuple of the form {:retry, reason}, where reason is any arbitrary term, or by raising a RuntimeError. Any other result is considered successful so the operation will not be retried and the result of the function will be returned as the result of call.

Link to this function

call!(fuse_name, retry_opts \\ %RetryOptions{}, function)

View Source
@spec call!(fuse_name(), ExternalService.RetryOptions.t(), retriable_function()) ::
  function_result :: any() | no_return()

Like call/3, but raises an exception if retries are exhausted or the fuse is blown.

Link to this function

call_async(fuse_name, retry_opts \\ %RetryOptions{}, function)

View Source

Asynchronous version of ExternalService.call.

Returns a Task that may be used to retrieve the result of the async call.

Link to this function

call_async_stream(enumerable, fuse_name, function)

View Source
@spec call_async_stream(
  Enumerable.t(),
  fuse_name(),
  (any() -> retriable_function_result())
) ::
  Enumerable.t()

Parallel, streaming version of ExternalService.call.

See call_async_stream/5 for full documentation.

Link to this function

call_async_stream(enumerable, fuse_name, retry_opts_or_async_opts, function)

View Source
@spec call_async_stream(
  Enumerable.t(),
  fuse_name(),
  ExternalService.RetryOptions.t() | (async_opts :: list()),
  (any() -> retriable_function_result())
) :: Enumerable.t()

Parallel, streaming version of ExternalService.call.

See call_async_stream/5 for full documentation.

Link to this function

call_async_stream(enumerable, fuse_name, retry_opts, async_opts, function)

View Source
@spec call_async_stream(
  Enumerable.t(),
  fuse_name(),
  ExternalService.RetryOptions.t(),
  async_opts :: list(),
  (any() -> retriable_function_result())
) :: Enumerable.t()

Parallel, streaming version of ExternalService.call.

This function uses Elixir's built-in Task.async_stream/3 function and the description below is taken from there.

Returns a stream that runs the given function function concurrently on each item in enumerable.

Each enumerable item is passed as argument to the given function function and processed by its own task. The tasks will be linked to the current process, similarly to async/1.

@spec reset_fuse(fuse_name()) :: :ok | {:error, :not_found}

Resets the given fuse.

After reset, the fuse will be unbroken with no melts.

Link to this function

start(fuse_name, options \\ [])

View Source
@spec start(fuse_name(), options()) :: :ok

Initializes a new fuse for a specific service.

The fuse_name is a term that uniquely identifies an external service within the scope of an application.

The options argument allows for controlling the circuit breaker behavior and rate-limiting behavior when making calls to the external service. See options/0 for details.

@spec stop(fuse_name()) :: :ok

Stops the fuse for a specific service.