PhoenixGenApi.ConfigPusher (PhoenixGenApi v2.11.0)

Copy Markdown View Source

A client-side module used on remote/service nodes to push configurations to the PhoenixGenApi gateway/server node.

Unlike ConfigReceiver (which is a GenServer running on the server), this module is a simple collection of functions that make RPC calls to the server node. It does not maintain any state of its own.

RPC Communication

All functions use :rpc.call/5 to communicate with the server node. If the server is unreachable or the RPC call fails, the result is wrapped in {:error, {:badrpc, reason}}.

Typical Usage

Remote nodes should call push_on_startup/3 during their application start (e.g., in the start/2 callback or a GenServer's init/handle_continue) to register their service configuration with the gateway.

Example

alias PhoenixGenApi.Structs.{FunConfig, PushConfig}
alias PhoenixGenApi.ConfigPusher

fun_configs = [
  %FunConfig{
    request_type: "get_data",
    service: :my_service,
    nodes: [Node.self()],
    choose_node_mode: :random,
    timeout: 5_000,
    mfa: {MyApp.Api, :get_data, []},
    arg_types: %{"id" => :string},
    response_type: :sync,
    version: "1.0.0"
  }
]

push_config = ConfigPusher.from_service_config(
  :my_service,
  [Node.self()],
  fun_configs,
  config_version: "1.0.0",
  module: MyApp.GenApi.Supporter,
  function: :get_config
)

# Push to gateway node
ConfigPusher.push_on_startup(:gateway@host, push_config)

# Or verify first
case ConfigPusher.verify(:gateway@host, :my_service, "1.0.0") do
  {:ok, :matched} -> :already_registered
  {:ok, :mismatch, _} -> ConfigPusher.push(:gateway@host, push_config)
  {:error, :not_found} -> ConfigPusher.push(:gateway@host, push_config)
end

Summary

Functions

Helper to create a PushConfig from existing service configuration data.

Pushes configurations to the server node without options.

Pushes configurations to the server node.

Pushes configs and handles the "push once on startup" pattern.

Verifies that the server has the given service and config version without options.

Verifies that the server has the given service and config version.

Functions

from_service_config(service, nodes, fun_configs, opts)

Helper to create a PushConfig from existing service configuration data.

This is a convenience function that builds a %PushConfig{} struct from the individual components, handling the optional fields for auto-pull and version checking.

Parameters

  • service - Service name (string or atom)
  • nodes - List of node names (atoms or strings)
  • fun_configs - List of FunConfig structs
  • opts - Options keyword list:
    • :config_version - Config version string (required)
    • :module - Module for auto-pull (optional)
    • :function - Function for auto-pull (optional)
    • :args - Args for auto-pull (default: [])
    • :version_module - Version check module (optional)
    • :version_function - Version check function (optional)
    • :version_args - Version check args (default: [])

Returns

A %PushConfig{} struct.

Raises

Raises ArgumentError if :config_version is not provided in opts.

Example

push_config = ConfigPusher.from_service_config(
  :my_service,
  [Node.self()],
  fun_configs,
  config_version: "1.0.0",
  module: MyApp.GenApi.Supporter,
  function: :get_config,
  version_module: MyApp.GenApi.Supporter,
  version_function: :get_config_version
)

push(server_node, push_config)

@spec push(node(), PhoenixGenApi.Structs.PushConfig.t()) ::
  {:ok, :accepted} | {:ok, :skipped, term()} | {:error, term()}

Pushes configurations to the server node without options.

Convenience function that calls push/3 with default options.

Parameters

  • server_node - The node name (atom) of the PhoenixGenApi gateway
  • push_config - A %PushConfig{} struct

Returns

Same as push/3.

push(server_node, push_config, opts)

@spec push(node(), PhoenixGenApi.Structs.PushConfig.t(), keyword()) ::
  {:ok, :accepted} | {:ok, :skipped, term()} | {:error, term()}

Pushes configurations to the server node.

Makes an RPC call to PhoenixGenApi.ConfigReceiver.push/2 on the server node. The server validates the PushConfig, checks the version, and stores the configs if the version is new (or if :force is set).

Parameters

  • server_node - The node name (atom) of the PhoenixGenApi gateway
  • push_config - A %PushConfig{} struct
  • opts - Options keyword list:
    • :timeout - RPC timeout in ms (default: 5000)
    • :force - Force push even if version matches (default: false)

Returns

  • {:ok, :accepted} - New configs were stored successfully
  • {:ok, :skipped, reason} - Push was skipped (e.g., version matches)
  • {:error, term()} - Push failed (includes :badrpc errors)

Example

{:ok, :accepted} = ConfigPusher.push(:gateway@host, push_config, timeout: 10_000)
{:ok, :skipped, :version_matches} = ConfigPusher.push(:gateway@host, push_config)
{:error, {:badrpc, :nodedown}} = ConfigPusher.push(:unreachable@host, push_config)

push_on_startup(server_node, push_config, opts)

@spec push_on_startup(node(), PhoenixGenApi.Structs.PushConfig.t(), keyword()) ::
  {:ok, :accepted} | {:ok, :skipped, term()} | {:error, term()}

Pushes configs and handles the "push once on startup" pattern.

This is the main entry point for remote nodes. It behaves the same as push/3 but logs the result at info level with more prominent messaging, making it easy to see in startup logs whether the configuration was successfully registered.

Call this function in your application's start/2 callback or a GenServer's handle_continue/2 to ensure your service is registered with the gateway on startup.

Parameters

  • server_node - The node name (atom) of the PhoenixGenApi gateway
  • push_config - A %PushConfig{} struct
  • opts - Options keyword list (same as push/3):
    • :timeout - RPC timeout in ms (default: 5000)
    • :force - Force push even if version matches (default: false)

Returns

Same as push/3.

Example

# In your application.ex
def start(_type, _args) do
  # ... start your supervision tree, then:
  ConfigPusher.push_on_startup(:gateway@host, push_config)
  # ...
end

# Or in a GenServer
def init(opts) do
  {:ok, initial_state, {:continue, :register_config}}
end

def handle_continue(:register_config, state) do
  ConfigPusher.push_on_startup(:gateway@host, push_config)
  {:noreply, state}
end

verify(server_node, service, config_version)

@spec verify(node(), String.t() | atom(), String.t()) ::
  {:ok, :matched} | {:ok, :mismatch, String.t()} | {:error, term()}

Verifies that the server has the given service and config version without options.

Convenience function that calls verify/4 with default options.

Parameters

  • server_node - The gateway node
  • service - Service name (string or atom)
  • config_version - Expected config version string

Returns

Same as verify/4.

verify(server_node, service, config_version, opts)

@spec verify(node(), String.t() | atom(), String.t(), keyword()) ::
  {:ok, :matched} | {:ok, :mismatch, String.t()} | {:error, term()}

Verifies that the server has the given service and config version.

Makes an RPC call to PhoenixGenApi.ConfigReceiver.verify/2 on the server node. Useful for checking whether a push is necessary before sending the full configuration.

Parameters

  • server_node - The gateway node
  • service - Service name (string or atom)
  • config_version - Expected config version string
  • opts - Options:
    • :timeout - RPC timeout in ms (default: 5000)

Returns

  • {:ok, :matched} - Server has the same version
  • {:ok, :mismatch, stored_version} - Server has a different version
  • {:error, :not_found} - Service is not known on the server
  • {:error, {:badrpc, reason}} - RPC call failed

Example

{:ok, :matched} = ConfigPusher.verify(:gateway@host, :my_service, "1.0.0")
{:ok, :mismatch, "0.9.0"} = ConfigPusher.verify(:gateway@host, :my_service, "1.0.0")
{:error, :not_found} = ConfigPusher.verify(:gateway@host, :unknown_service, "1.0.0")