View Source ExternalService.Gateway behaviour (external_service v1.1.4)

Defines a gateway to an external service.

ExternalService.Gateway allows for defining module-based gateways to external services. Instead of explicitly starting a fuse with its configuration and separately passing in retry options on each call to the service, a module-based gateway allows one to specify default fuse and retry options at the module level.

When a module uses the ExternalService.Gateway module, an implementation of the ExternalService.Gateway behaviour will be generated using the fuse, retry, and rate-limit options provided to the use ExternalService.Gateway statement. See the documentation for the various callbacks in this module for more details.

example

Example

defmodule MyApp.SomeService do
  use ExternalService.Gateway,
    fuse: [
      # Tolerate 5 failures for every 1 second time window.
      strategy: {:standard, 5, 10_000},
      # Reset the fuse 5 seconds after it is blown.
      refresh: 5_000
    ],
    # Limit to 5 calls per second.
    rate_limit: {5, :timer.seconds(1)},
    retry: [
      # Use linear backoff. Exponential backoff is also available.
      backoff: {:linear, 100, 1},
      # Stop retrying after 5 seconds.
      expiry: 5_000
    ]

  def call_the_service(params) do
    external_call fn ->
      # Call the service with params, then return the result or :retry.
      case do_call(params) do
        {:ok, result} -> {:ok, result}
        {:error, reason} -> {:retry, reason}
      end
    end
  end
end

initialization-and-configuration

Initialization and configuration

Gateways must be started (preferably under a supervisor) before being used.

To initialize a gateway with its default configuration, just add the gateway module to the top-level supervisor for your application:

children = [
  MyApp.SomeService
]

Supervisor.start_link(children, strategy: :one_for_one)

It is also possible to override the default configuration for the gateway by passing options to the child specification that is passed to the supervisor. This can be useful for using different configuration in the test environment. For example:

some_service_config = Application.get_env(:my_app, :some_service, [])

children = [
  {MyApp.SomeService, some_service_config}
]

Supervisor.start_link(children, strategy: :one_for_one)

Link to this section Summary

Callbacks

Invoked to call the given function using the retry options configured for the gateway.

Invoked to call the given function using custom retry options.

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

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

Asynchronous version of external_call/1.

Asynchronous version of external_call/2.

Parallel, streaming version of external_call/1.

Parallel, streaming version of external_call/2.

Parallel, streaming version of external_call/2.

Link to this section Callbacks

Link to this callback

external_call(retriable_function)

View Source
@callback external_call(ExternalService.retriable_function()) ::
  ExternalService.error() | (function_result :: any())

Invoked to call the given function using the retry options configured for the gateway.

See ExternalService.call/3 for more information.

Link to this callback

external_call(t, retriable_function)

View Source
@callback external_call(
  ExternalService.RetryOptions.t(),
  ExternalService.retriable_function()
) ::
  ExternalService.error() | (function_result :: any())

Invoked to call the given function using custom retry options.

See ExternalService.call/3 for more information.

Link to this callback

external_call!(retriable_function)

View Source
@callback external_call!(ExternalService.retriable_function()) ::
  function_result :: any() | no_return()

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

See ExternalService.call!/3 for more information.

Link to this callback

external_call!(t, retriable_function)

View Source
@callback external_call!(
  ExternalService.RetryOptions.t(),
  ExternalService.retriable_function()
) ::
  function_result :: any() | no_return()

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

See ExternalService.call!/3 for more information.

Link to this callback

external_call_async(retriable_function)

View Source
@callback external_call_async(ExternalService.retriable_function()) :: Task.t()

Asynchronous version of external_call/1.

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

See ExternalService.call_async for more information.

Link to this callback

external_call_async(t, retriable_function)

View Source
@callback external_call_async(
  ExternalService.RetryOptions.t(),
  ExternalService.retriable_function()
) ::
  Task.t()

Asynchronous version of external_call/2.

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

See ExternalService.call_async for more information.

Link to this callback

external_call_async_stream(t, function)

View Source
@callback external_call_async_stream(
  Enumerable.t(),
  (any() -> ExternalService.retriable_function_result())
) :: Enumerable.t()

Parallel, streaming version of external_call/1.

See ExternalService.call_async_stream/5 for more information.

Link to this callback

external_call_async_stream(t, arg2, function)

View Source
@callback external_call_async_stream(
  Enumerable.t(),
  ExternalService.RetryOptions.t() | (async_opts :: list()),
  (any() -> ExternalService.retriable_function_result())
) :: Enumerable.t()

Parallel, streaming version of external_call/2.

See ExternalService.call_async_stream/5 for more information.

Link to this callback

external_call_async_stream(t, t, async_opts, function)

View Source
@callback external_call_async_stream(
  Enumerable.t(),
  ExternalService.RetryOptions.t(),
  async_opts :: list(),
  (any() -> ExternalService.retriable_function_result())
) :: Enumerable.t()

Parallel, streaming version of external_call/2.

See ExternalService.call_async_stream/5 for more information.