hex logo Hex
Packages Pricing Docs
Log In
Packages Pricing Docs Log In
Packages

statsig_elixir

0.15.2-beta.2602180309
0.20.3-beta.2607250300 0.20.3-beta.2607240300 0.20.2 0.20.2-rc.2607201629 0.20.2-beta.2607230301 0.20.2-beta.2607220301 0.20.2-beta.2607180300 0.20.2-beta.2607170300 0.20.1 0.20.1-rc.2607140134 0.20.1-rc.2607132133 0.20.1-beta.2607150300 0.20.0 0.19.9-rc.2607090505 0.19.9-rc.2607010924 0.19.9-beta.2607110300 0.19.9-beta.2607100302 0.19.9-beta.2607090302 0.19.9-beta.2607080301 0.19.9-beta.2607020303 0.19.9-beta.2607010304 0.19.9-beta.2606260304 0.19.8 0.19.7-rc.2606232103 0.19.7-beta.2606240303 0.19.7-beta.2606190306 0.19.7-beta.2606180304 0.19.6 0.19.6-rc.2606161624 0.19.6-rc.2606151903 0.19.6-beta.2606170305 0.19.6-beta.2606100304 0.19.5 0.19.5-rc.2606050349 0.19.5-beta.2606060303 0.19.4 0.19.4-rc.2605212136 0.19.3 0.19.3-beta.2604211739 0.19.2 0.19.2-rc.2604140138 0.19.2-beta.2604150312 0.19.1 0.19.1-rc.2604121707 0.19.1-beta.2604130314 0.19.1-beta.2604110309 0.19.1-beta.2604100313 0.19.0 0.18.2-rc.2604080018 0.18.2-beta.2604080312 0.18.1 0.18.1-rc.2604070138 0.18.1-beta.2604072116 0.18.0 0.17.3-rc.2603272156 0.17.3-beta.2603290312 0.17.3-beta.2603280308 0.17.3-beta.2603250310 0.17.2 0.17.2-rc.2603240138 0.17.2-beta.2603241852 0.17.1 0.17.1-rc.2603201903 0.17.1-rc.2603192323 0.17.1-beta.2603210301 0.17.1-beta.2603200305 0.17.1-beta.2603181954 0.17.0 0.16.6-rc.2603180529 0.16.6-rc.2603170138 0.16.6-beta.2603181807 0.16.5 0.16.5-rc.2603131810 0.16.5-beta.2603130304 0.16.4 0.16.4-rc.2603092140 0.16.4-beta.2603110302 0.16.4-beta.2603060304 0.16.4-beta.2603051742 0.16.4-beta.2603040814 0.16.4-beta.2603040303 0.16.3 0.16.3-rc.2602271954 0.16.3-rc.2602270324 0.16.3-rc.2602240138 0.16.3-beta.2603040747 0.16.3-beta.2603021916 0.16.3-beta.2602280254 0.16.3-beta.2602262056 0.16.3-beta.2602250307 0.16.3-beta.2602240529 0.16.2 0.16.2-rc.2602202152 0.16.2-rc.2602200042 0.16.2-beta.2602210300 0.16.2-beta.2602200305 0.16.1 0.16.1-rc.2602180406 0.16.1-beta.2602190307 0.16.0 0.15.2-rc.2602172254 0.15.2-rc.2602140111 0.15.2-rc.2602130016 0.15.2-rc.2602100139 0.15.2-rc.2602030138 0.15.2-beta.2602180309 0.15.2-beta.2602150309 0.15.2-beta.2602140304 0.15.2-beta.2602130310 0.15.2-beta.2602122245 0.15.2-beta.2602122035 0.15.2-beta.2602120040 0.15.2-beta.2602110310 0.15.2-beta.2602050305 0.15.2-beta.2602040304 0.15.2-beta.2602031515 0.15.1 0.15.1-rc.2601270136 0.15.1-beta.2601310133 0.15.1-beta.2601301825 0.15.1-beta.2601300156 0.15.1-beta.2601292313 0.15.1-beta.2601280249 0.15.0 0.14.2-rc.2601230113 0.14.2-rc.2601200136 0.14.2-rc.2601130135 0.14.2-rc.2601062017 0.14.2-rc.2512230135 0.14.2-beta.2601262335 0.14.2-beta.2601240243 0.14.2-beta.2601230247 0.14.2-beta.2601220251 0.14.2-beta.2601210246 0.14.2-beta.2601170240 0.14.2-beta.2601160247 0.14.2-beta.2601140250 0.14.2-beta.2601130116 0.14.2-beta.2601100241 0.14.2-beta.2601070246 0.14.2-beta.2512310244 0.14.2-beta.2512240241 0.14.1 0.14.1-rc.2512190311 0.14.1-rc.2512162207 0.14.1-rc.2512160223 0.14.1-beta.2512200239 0.14.1-beta.2512190242 0.14.1-beta.2512170241 0.14.0 0.13.1-beta.2512140246 0.13.1-beta.2512130201 0.13.1-beta.2512120242 0.13.1-beta.2512110242 0.13.1-beta.2512110007 0.13.1-beta.2512102250 0.13.1-beta.2512102139 0.13.1-beta.2512100241 0.13.1-beta.2512051931 0.13.1-beta.2512050240 0.12.1 0.12.1-rc.2511121816 0.12.1-rc.2511110014 0.12.1-beta.2511110238 0.12.0 0.11.2-rc.2511040014 0.11.2-beta.2511050238 0.11.2-beta.2511032240 0.11.2-beta.2511032212 0.11.2-beta.2511030239 0.11.2-beta.2510310237 0.11.1 0.11.1-rc.2510292219 0.11.1-rc.2510280013 0.11.1-beta.2510300237 0.11.1-beta.2510290239 0.11.0 0.10.3-rc.2510210409 0.10.3-rc.2510210014 0.10.3-rc.6 0.10.3-beta.2510250234 0.10.3-beta.2510240234 0.10.3-beta.2510230235 0.10.3-beta.2510220237 0.10.2 0.10.2-rc.2510141845 0.10.2-beta.2510180231 0.10.2-beta.2510172041 0.10.2-beta.2510170235 0.10.2-beta.2510160235 0.10.2-beta.2510152259 0.10.2-beta.2510152125 0.10.2-beta.2510151849 0.10.2-beta.2510150236 0.10.2-beta.2510142155 0.10.2-beta.2510142023 0.10.1 0.10.0 0.10.0-rc.2510090432 0.10.0-rc.2510070136 0.10.0-beta.2510120235 0.10.0-beta.2510102126 0.10.0-beta.2510100234 0.10.0-beta.2510090234 0.10.0-beta.2510072144 0.9.6-beta.2510020232 0.9.5-rc.2510030411 0.9.5-rc.2510020138 0.9.5-beta.2510010238 0.9.4-rc.2509300113 0.9.4-beta.2509252256 0.9.3 0.9.3-beta.2509250234 0.9.3-beta.2509240232 0.9.3-beta.2509231844 0.9.2-rc.2509221315 0.9.2-beta.2509190233 0.9.2-beta.2509180233 0.9.2-beta.2509180231 0.9.2-beta.2509170231 0.9.1 0.9.1-rc.2509190115 0.9.1-rc.2509181925 0.9.1-rc.2509171909 0.9.0-rc.1 0.8.9-beta.2509161804 0.8.9-beta.2509160231 0.8.8-beta.2509130225 0.8.8-beta.2509112152 0.8.8-beta.2509112049 0.8.8-beta.2509110233 0.8.7 0.8.7-rc.2509102057 0.8.7-rc.2509102017 0.8.7-rc.2509100003 0.8.7-rc.2509092342 0.8.7-beta.2509092208 0.8.6 0.8.6-rc.2509082013 0.8.6-beta.2509040231 0.8.6-beta.2509020235 0.8.5 0.8.5-beta.2508300230 0.8.4 0.8.3 0.8.3-beta.2508280233 0.8.2 0.8.2-rc.2508282224 0.8.1 0.8.1-rc.2508271913 0.8.1-rc.2508262341 0.8.1-rc.2508251314 0.8.0 0.7.4-rc.2508222145 0.7.4-rc.2508220107 0.7.4-rc.2508220104 0.7.4-rc.2508220101 0.7.4-rc.2508220057 0.7.4-rc.2508220049 0.7.4-rc.2508220046 0.7.4-rc.2508220041 0.7.4-rc.2508220033 0.7.4-rc.2508220032 0.7.4-rc.2508220027 0.7.4-rc.2508220022 0.7.4-rc.2508220017 0.7.4-rc.2508220010 0.7.4-rc.2508220006 0.7.4-rc.2508220000 0.7.4-rc.2508212357 0.7.4-rc.2508212349 0.7.4-rc.2508202203 0.7.4-rc.2508202034 0.7.4-rc.2508191829 0.7.4-beta.2508220235 0.7.4-beta.2508210235 0.7.4-beta.2508200235 0.7.4-beta.2508190236 0.7.4-beta.2508160236 0.7.4-beta.2508150240 0.0.6-beta.7 0.0.6-beta.6 0.0.2 retired 0.0.1 retired

A performant elixir SDK for Statsig feature gates and experiments using Rustler

HexDocs

Current section

Files

Jump to
Readme
284 Versions
2 Dependencies
Dependants
Files
Activity
Readme 284 Versions 2 Dependencies Dependants Files Activity
statsig_elixir lib statsig data_store.ex
Raw

21 files

  • lib
    • statsig
      • data_store.ex
      • dynamic_config.ex
      • experiment.ex
      • feature_gate.ex
      • layer.ex
      • native_bindings.ex
      • options.ex
      • user.ex
    • statsig.ex
  • native
    • statsig_elixir
      • src
        • data_store_nfi.rs
        • lib.rs
        • statsig_nfi.rs
        • statsig_options_nfi.rs
        • statsig_types_nfi.rs
        • statsig_user_nfi.rs
      • Cargo.toml
      • README.md
  • LICENSE
  • README.md
  • checksum-Elixir.Statsig.NativeBindings.exs
  • mix.exs

    No matching files

    Package files

      No matching files

      lib/statsig/data_store.ex

      defmodule Statsig.DataStore.Reference do
      @moduledoc false
      @enforce_keys [:pid]
      defstruct [:pid]
      @type t :: %__MODULE__{pid: pid()}
      end
      defmodule Statsig.DataStore.Response do
      @moduledoc """
      Response struct returned from `handle_get/2`.
      """
      defstruct result: nil, time: nil
      @type t :: %__MODULE__{result: nil | String.t(), time: nil | non_neg_integer()}
      end
      defmodule Statsig.DataStore do
      @moduledoc """
      Behaviour and helper APIs for implementing a custom Statsig data store in Elixir.
      A data store implementation is a module that implements the callbacks in this behaviour.
      Use `start_link/3` to launch the bridge process and pass the returned
      `%Statsig.DataStore.Reference{}` into `Statsig.Options`.
      """
      alias Statsig.DataStore.Reference
      alias Statsig.DataStore.Server
      @typedoc "Opaque state returned from user callbacks."
      @type state :: term()
      @callback init(init_arg :: term()) :: {:ok, state()} | {:error, term()}
      @callback handle_initialize(state()) :: {:ok, state()} | {:error, term()}
      @callback handle_shutdown(state()) :: {:ok, state()} | {:error, term()}
      @callback handle_get(String.t(), state()) ::
      {:ok, %Statsig.DataStore.Response{}, state()} | {:error, term()}
      @callback handle_set(String.t(), String.t(), non_neg_integer() | nil, state()) ::
      {:ok, state()} | {:error, term()}
      @callback handle_support_polling_updates_for(String.t(), state()) ::
      {:ok, boolean(), state()} | {:error, term()}
      @optional_callbacks handle_initialize: 1,
      handle_shutdown: 1,
      handle_set: 4,
      handle_support_polling_updates_for: 2
      @doc """
      Starts a bridge process for the provided implementation module.
      Returns `{:ok, %Statsig.DataStore.Reference{}}` which can be assigned to
      `%Statsig.Options{data_store: reference}`.
      """
      @spec start_link(module(), term(), Keyword.t()) ::
      {:ok, Reference.t()} | {:error, term()}
      def start_link(module, init_arg \\ nil, opts \\ []) do
      case Server.start_link(module, init_arg, opts) do
      {:ok, pid} -> {:ok, %Reference{pid: pid}}
      other -> other
      end
      end
      @doc """
      Stops the bridge process for the given reference.
      """
      @spec stop(Reference.t(), term(), non_neg_integer()) :: :ok
      def stop(%Reference{pid: pid}, reason \\ :normal, timeout \\ 5_000) do
      GenServer.stop(pid, reason, timeout)
      end
      end
      defmodule Statsig.DataStore.Server do
      @moduledoc false
      use GenServer
      require Logger
      alias Statsig.DataStore.Response
      @request_tag :statsig_data_store_request
      @default_bindings Statsig.NativeBindings
      @spec start_link(module(), term(), Keyword.t()) :: GenServer.on_start()
      def start_link(module, init_arg, opts) do
      {bindings_module, gen_server_opts} =
      Keyword.put_new(opts, :bindings_module, @default_bindings)
      |> Keyword.pop(:bindings_module)
      GenServer.start_link(
      __MODULE__,
      %{module: module, module_state: nil, bindings_module: bindings_module, init_arg: init_arg},
      gen_server_opts
      )
      end
      @impl true
      def init(%{module: module, init_arg: init_arg} = state) do
      case safe_apply(module, :init, [init_arg]) do
      {:ok, module_state} ->
      {:ok,
      state
      |> Map.put(:module_state, module_state)
      |> Map.delete(:init_arg)}
      {:error, reason} ->
      {:stop, reason}
      other ->
      {:stop, {:bad_return, {module, :init, other}}}
      end
      end
      @impl true
      def handle_info(
      {@request_tag, request_ref, request_type, payload},
      %{module: module} = state
      ) do
      case dispatch(request_type, payload, state) do
      {:ok, reply_payload, new_module_state} ->
      send_reply(state.bindings_module, request_ref, reply_payload)
      {:noreply, %{state | module_state: new_module_state}}
      {:error, reason} ->
      send_error(state.bindings_module, request_ref, reason)
      {:noreply, state}
      :unknown ->
      send_error(
      state.bindings_module,
      request_ref,
      "Unknown data store request #{inspect(request_type)}"
      )
      {:noreply, state}
      end
      end
      @impl true
      def handle_info(message, state) do
      Logger.debug("Statsig.DataStore.Server received unexpected message: #{inspect(message)}")
      {:noreply, state}
      end
      defp dispatch(:initialize, _payload, state) do
      case call_without_value(state.module, :handle_initialize, 1, [state.module_state]) do
      {:ok, new_state} -> {:ok, :ok, new_state}
      :noop -> {:ok, :ok, state.module_state}
      {:error, reason} -> {:error, reason}
      end
      end
      defp dispatch(:shutdown, _payload, state) do
      case call_without_value(state.module, :handle_shutdown, 1, [state.module_state]) do
      {:ok, new_state} -> {:ok, :ok, new_state}
      :noop -> {:ok, :ok, state.module_state}
      {:error, reason} -> {:error, reason}
      end
      end
      defp dispatch(:get, key, state) do
      case maybe_call(state.module, :handle_get, 2, [key, state.module_state], :missing) do
      :missing ->
      {:error, "handle_get/2 is not implemented for #{inspect(state.module)}"}
      {:ok, %Response{} = response, new_state} ->
      {:ok, response, new_state}
      {:ok, %Response{} = response} ->
      {:ok, response, state.module_state}
      {:error, reason} ->
      {:error, reason}
      other ->
      {:error, {:bad_return, {state.module, :handle_get, other}}}
      end
      end
      defp dispatch(:set, {key, value, time}, state) do
      case call_without_value(
      state.module,
      :handle_set,
      4,
      [key, value, time, state.module_state]
      ) do
      {:ok, new_state} -> {:ok, :ok, new_state}
      :noop -> {:ok, :ok, state.module_state}
      {:error, reason} -> {:error, reason}
      end
      end
      defp dispatch(:support_polling_updates_for, path, state) do
      default = {:ok, false, state.module_state}
      case maybe_call(
      state.module,
      :handle_support_polling_updates_for,
      2,
      [path, state.module_state],
      default
      ) do
      {:ok, bool, new_state} when is_boolean(bool) ->
      {:ok, bool, new_state}
      {:ok, bool} when is_boolean(bool) ->
      {:ok, bool, state.module_state}
      {:ok, other, _new_state} ->
      {:error, {:invalid_return, other}}
      {:error, reason} ->
      {:error, reason}
      other ->
      {:error, {:bad_return, {state.module, :handle_support_polling_updates_for, other}}}
      end
      end
      defp dispatch(_type, _payload, _state), do: :unknown
      defp call_without_value(module, fun, arity, args) do
      case maybe_call(module, fun, arity, args, :ok) do
      {:ok, new_state} -> {:ok, new_state}
      {:error, reason} -> {:error, reason}
      :ok -> :noop
      other -> {:error, {:bad_return, {module, fun, other}}}
      end
      end
      defp maybe_call(module, fun, arity, args, default) do
      if function_exported?(module, fun, arity) do
      safe_apply(module, fun, args)
      else
      default
      end
      end
      defp safe_apply(module, fun, args) do
      try do
      apply(module, fun, args)
      rescue
      exception -> {:error, Exception.message(exception)}
      catch
      kind, reason -> {:error, {kind, reason}}
      end
      end
      defp send_reply({module, context}, request_ref, payload) do
      _ = module.data_store_reply(context, request_ref, payload)
      end
      defp send_reply(module, request_ref, payload) do
      _ = module.data_store_reply(request_ref, payload)
      end
      defp send_error({module, context}, request_ref, reason) do
      reason = format_reason(reason)
      _ = module.data_store_reply_error(context, request_ref, reason)
      end
      defp send_error(module, request_ref, reason) do
      reason = format_reason(reason)
      _ = module.data_store_reply_error(request_ref, reason)
      end
      defp format_reason(reason) when is_binary(reason), do: reason
      defp format_reason({:bad_return, {module, fun, value}}),
      do: "Invalid return from #{inspect(module)}.#{fun}: #{inspect(value)}"
      defp format_reason(reason), do: inspect(reason)
      end
      hex logo Hex
      About Blog Sponsors Status Advisories
      Documentation FAQ Specifications Report Client Issue Report General Issue Report Security Issue Contact Support
      Code of Conduct Terms of Service Privacy Policy Copyright Policy Dispute Policy

      Copyright 2015. Six Colors AB.

      Powered by the Erlang VM and the Elixir Programming Language

      Search filters

      Type any of these into the search box. They can be combined with free text which searches package names and descriptions.

      Operator Description Example
      name: Match package name. Supports * wildcards and repo/package form name:phx* or name:hexpm/phoenix
      description: Full-text search of package descriptions description:auth
      depends: Packages depending on a given package. Supports repo:package form depends:ecto or depends:hexpm:ecto
      build_tool: Filter by build tool build_tool:mix
      updated_after: Packages updated after an ISO8601 datetime updated_after:2025-01-01T00:00:00Z
      extra: Match custom metadata (key,value). Nested keys are separated by commas extra:license,MIT

      Wrap values in double quotes to include spaces, e.g. name:"my package".