defmodule ConfigCat.CachePolicy do @moduledoc """ Represents the [polling mode](https://configcat.com/docs/sdk-reference/elixir#polling-modes) used by ConfigCat. The *ConfigCat SDK* supports 3 different polling mechanisms to acquire the setting values from *ConfigCat*. After the latest setting values are downloaded, they are stored in the internal cache and all requests are served from there. With the following polling modes, you can customize the SDK to best fit to your application's lifecycle. ## Auto polling (default) The *ConfigCat SDK* downloads the latest values and stores them automatically on a regular schedule. See `auto/1` below for details. ## Lazy loading When calling any of the public API functions (like `get_value()`), the *ConfigCat SDK* downloads the latest setting values if they are not present or have expired. In this case the function will wait until the settings have been fetched before returning. See `lazy/1` below for details. ## Manual polling Manual polling gives you full control over when the setting values are downloaded. *ConfigCat SDK* will not update them automatically. Calling `ConfigCat.force_refresh/1` is your application's responsibility. See `manual/0` below for details. """ @behaviour ConfigCat.CachePolicy.Behaviour alias ConfigCat.CachePolicy.Auto alias ConfigCat.CachePolicy.Behaviour alias ConfigCat.CachePolicy.Lazy alias ConfigCat.CachePolicy.Manual require ConfigCat.Constants, as: Constants @typedoc "Options for auto-polling mode." @type auto_options :: [ {:max_init_wait_time_seconds, non_neg_integer()} | {:poll_interval_seconds, pos_integer()} ] @typedoc "Options for lazy-polling mode." @type lazy_options :: [{:cache_refresh_interval_seconds, non_neg_integer()}] @typedoc "Callback to call when configuration changes." @type on_changed_callback :: (-> :ok) @typedoc false @type option :: {:cache_policy, t()} | {:fetcher, module()} | {:instance_id, ConfigCat.instance_id()} | {:offline, boolean()} @typedoc false @type options :: [option] @typedoc "The polling mode" @opaque t :: Auto.t() | Lazy.t() | Manual.t() @doc """ Auto-polling mode. The *ConfigCat SDK* downloads the latest values and stores them automatically on a regular schedule. Use the `max_init_wait_time_seconds` option to set the maximum waiting time between initialization and the first config acquisition. Defaults to 5 seconds if not specified. ```elixir ConfigCat.CachePolicy.auto(max_init_wait_time_seconds: 5) ``` Use the `poll_interval_seconds` option to change the polling interval. Defaults to 60 seconds if not specified. ```elixir ConfigCat.CachePolicy.auto(poll_interval_seconds: 60) ``` """ @spec auto(auto_options()) :: t() def auto(options \\ []) do Auto.new(options) end @doc """ Lazy polling mode. When calling any of the public API functions (like `get_value()`), the *ConfigCat SDK* downloads the latest setting values if they are not present or have expired. In this case the function will wait until the settings have been fetched before returning. Use the required `cache_refresh_interval_seconds` option to set the cache lifetime. ```elixir ConfigCat.CachePolicy.lazy(cache_refresh_interval_seconds: 300) ``` """ @spec lazy(lazy_options()) :: t() def lazy(options) do Lazy.new(options) end @doc """ Manual polling mode. Manual polling gives you full control over when the setting values are downloaded. *ConfigCat SDK* will not update them automatically. Calling `ConfigCat.force_refresh/1` is your application's responsibility. ```elixir ConfigCat.CachePolicy.manual() ``` """ @spec manual :: t() def manual do Manual.new() end @doc false @spec child_spec(options()) :: Supervisor.child_spec() def child_spec(options) do %policy_module{} = Keyword.fetch!(options, :cache_policy) policy_module.child_spec(options) end @impl Behaviour def get(instance_id) do instance_id |> via_tuple() |> GenServer.call(:get, Constants.fetch_timeout()) end @impl Behaviour def offline?(instance_id) do instance_id |> via_tuple() |> GenServer.call(:offline?, Constants.fetch_timeout()) end @impl Behaviour def set_offline(instance_id) do instance_id |> via_tuple() |> GenServer.call(:set_offline, Constants.fetch_timeout()) end @impl Behaviour def set_online(instance_id) do instance_id |> via_tuple() |> GenServer.call(:set_online, Constants.fetch_timeout()) end @impl Behaviour def force_refresh(instance_id) do instance_id |> via_tuple() |> GenServer.call(:force_refresh, Constants.fetch_timeout()) end @doc false @spec via_tuple(ConfigCat.instance_id()) :: {:via, module(), term()} def via_tuple(instance_id) do {:via, Registry, {ConfigCat.Registry, {__MODULE__, instance_id}}} end end