PushX.Config (PushX v0.14.0)

Copy Markdown View Source

Configuration management for PushX.

Configuration Options

APNS (Apple Push Notification Service)

  • :apns_key_id - The Key ID from Apple Developer Portal
  • :apns_team_id - Your Apple Developer Team ID
  • :apns_private_key - The private key, either:
    • A raw PEM string
    • {:file, "/path/to/AuthKey.p8"}
    • {:system, "ENV_VAR_NAME"}
  • :apns_mode - :prod or :sandbox (default: :prod)

FCM (Firebase Cloud Messaging)

  • :fcm_project_id - Your Firebase project ID
  • :fcm_credentials - Service account credentials, either:
    • {:file, "/path/to/service-account.json"}
    • {:json, "...json string..."}
    • {:system, "ENV_VAR_NAME"} (expects JSON string)
  • :fcm_token_fetcher - (optional, advanced) bring your own OAuth: an {module, function, args} tuple that replaces the Goth process PushX would otherwise start. See fcm_token_fetcher/0.

Testing

  • :delivery - :live (default) or :test — record sends locally instead of contacting APNS/FCM; see PushX.Test

Finch Pool

  • :finch_name - Name of the Finch pool (default: PushX.Finch)
  • :finch_pool_size - Connections per pool (default: 25)
  • :finch_pool_count - Number of pools (default: 2)

Request Timeouts

  • :receive_timeout - Timeout for receiving response in ms (default: 15_000)
  • :pool_timeout - Timeout for acquiring connection from pool in ms (default: 5_000)
  • :connect_timeout - TCP connection timeout in ms (default: 10_000)

Retry Settings

  • :retry_enabled - Enable automatic retry (default: true)
  • :retry_max_attempts - Maximum retry attempts (default: 3)
  • :retry_base_delay_ms - Base delay in milliseconds (default: 10_000)
  • :retry_max_delay_ms - Maximum delay in milliseconds (default: 60_000)
  • :reconnect_cooldown_ms - Minimum time between automatic Finch pool restarts triggered by connection errors, per pool (default: 5_000); see PushX.ReconnectGuard. Manual PushX.reconnect/0 is not gated.

Batch Sending

  • :batch_concurrency - Default :concurrency for PushX.push_batch/4, push_batch_stream/4 and the provider send_batch/3 functions (default: 50)

Circuit Breaker (opt-in)

  • :circuit_breaker_enabled - (default: false)
  • :circuit_breaker_threshold - consecutive failures that open the breaker (default: 5)
  • :circuit_breaker_cooldown_ms - open → half-open delay (default: 30_000)

See PushX.CircuitBreaker.

Rate Limiting (opt-in)

  • :rate_limit_enabled - (default: false)
  • :rate_limit_apns, :rate_limit_fcm - max sends per window per provider (default: 5_000)
  • :rate_limit_window_ms - fixed window length (default: 1_000)

See PushX.RateLimiter.

Token Cleanup

  • :on_invalid_token - {module, function, args} invoked asynchronously as apply(module, function, [provider, token | args]) whenever a response says the token should be removed (PushX.Response.should_remove_token?/1); see the README's "Token Cleanup Callback".

Internal / test-only

  • :apns_url_override, :fcm_url_override - point the real send paths at a local HTTP server. Used by PushX's own test suite; not for production. For testing your application use :delivery (PushX.Test) instead.

Example Configuration

config :pushx,
  apns_key_id: "ABC123DEFG",
  apns_team_id: "TEAM123456",
  apns_private_key: {:file, "priv/keys/AuthKey.p8"},
  apns_mode: :prod,
  fcm_project_id: "my-project-id",
  fcm_credentials: {:file, "priv/keys/firebase.json"}

Summary

Functions

Checks if APNS is configured.

Gets the APNS Key ID.

Gets the APNS mode (:prod or :sandbox).

Gets the APNS private key content. Supports file paths, environment variables, and raw strings.

Gets the APNS Team ID.

Default per-task timeout for batch sends, in milliseconds.

Like batch_timeout_ms/0, but for a specific per-call retry policy: retry: :none means a single attempt, so the budget is the 30 s floor.

Gets the cooldown time in milliseconds before the circuit transitions from :open to :half_open. Default: 30 seconds.

Checks if the circuit breaker is enabled. Default: false (opt-in feature).

Gets the number of consecutive failures before the circuit opens. Default: 5.

Gets the TCP connection timeout in milliseconds. Default: 10 seconds.

Delivery mode: :live (default) sends to the providers; :test records sends locally instead — see PushX.Test.

Checks if FCM is configured.

Gets the FCM credentials for Goth. Returns a map suitable for Goth configuration.

Gets the FCM project ID.

Returns the custom FCM OAuth token fetcher, if one is configured.

Gets the Finch pool name.

Gets the Finch pool count (number of connection pools).

Gets the Finch pool size (connections per pool).

Returns the Finch request options with configured timeouts.

Gets a configuration value.

Gets a required configuration value. Raises if the value is not configured.

Gets the callback for invalid token cleanup.

Gets the pool timeout (time to wait for a connection from pool) in milliseconds. Default: 5 seconds.

Gets the receive timeout (time to wait for response data) in milliseconds. Default: 15 seconds.

request_timeout() deprecated

Gets the overall request timeout in milliseconds. Default: 30 seconds.

Gets the base delay for exponential backoff in milliseconds. Default: 10 seconds (Google's recommended minimum).

Checks if retry is enabled.

Gets the maximum number of retry attempts.

Gets the maximum delay for exponential backoff in milliseconds. Default: 60 seconds.

Functions

apns_configured?()

@spec apns_configured?() :: boolean()

Checks if APNS is configured.

apns_key_id()

@spec apns_key_id() :: String.t()

Gets the APNS Key ID.

apns_mode()

@spec apns_mode() :: :prod | :sandbox

Gets the APNS mode (:prod or :sandbox).

apns_private_key()

@spec apns_private_key() :: String.t()

Gets the APNS private key content. Supports file paths, environment variables, and raw strings.

apns_team_id()

@spec apns_team_id() :: String.t()

Gets the APNS Team ID.

batch_timeout_ms()

@spec batch_timeout_ms() :: pos_integer()

Default per-task timeout for batch sends, in milliseconds.

Retries block the sending task (see PushX.Retry), so a batch task can legitimately outlive any flat timeout while it backs off between attempts. When retries are enabled this covers the worst-case retry budget:

attempts × (receive_timeout + pool_timeout)
  + (attempts  1) × max(retry_max_delay_ms, 60s rate-limit delay)

With retries disabled — globally (retry_enabled: false) or for the call (retry: :none, see batch_timeout_ms/1) — it is 30 seconds. An explicit :timeout option on PushX.push_batch/4 / send_batch/3 always takes precedence.

batch_timeout_ms(list)

@spec batch_timeout_ms([{:retry, :blocking | :none}]) :: pos_integer()

Like batch_timeout_ms/0, but for a specific per-call retry policy: retry: :none means a single attempt, so the budget is the 30 s floor.

circuit_breaker_cooldown_ms()

@spec circuit_breaker_cooldown_ms() :: pos_integer()

Gets the cooldown time in milliseconds before the circuit transitions from :open to :half_open. Default: 30 seconds.

circuit_breaker_enabled?()

@spec circuit_breaker_enabled?() :: boolean()

Checks if the circuit breaker is enabled. Default: false (opt-in feature).

circuit_breaker_threshold()

@spec circuit_breaker_threshold() :: pos_integer()

Gets the number of consecutive failures before the circuit opens. Default: 5.

connect_timeout()

@spec connect_timeout() :: pos_integer()

Gets the TCP connection timeout in milliseconds. Default: 10 seconds.

delivery()

@spec delivery() :: :live | :test

Delivery mode: :live (default) sends to the providers; :test records sends locally instead — see PushX.Test.

fcm_configured?()

@spec fcm_configured?() :: boolean()

Checks if FCM is configured.

fcm_credentials()

@spec fcm_credentials() :: map() | {:file, String.t()}

Gets the FCM credentials for Goth. Returns a map suitable for Goth configuration.

fcm_project_id()

@spec fcm_project_id() :: String.t()

Gets the FCM project ID.

fcm_token_fetcher()

@spec fcm_token_fetcher() :: {module(), atom(), list()} | nil

Returns the custom FCM OAuth token fetcher, if one is configured.

By default PushX starts a Goth process (PushX.Goth) from :fcm_credentials and calls Goth.fetch/1 before every FCM send. Set :fcm_token_fetcher to an {module, function, args} tuple to supply the OAuth access token yourself instead — for example to reuse a Goth process your application already runs, or to fetch tokens from a secrets service:

# config/runtime.exs
config :pushx,
  fcm_project_id: "my-project",
  fcm_token_fetcher: {MyApp.PushOAuth, :fetch, []}

defmodule MyApp.PushOAuth do
  # PushX passes the Goth name it would have used as the first argument;
  # a fetcher that reuses your own Goth simply ignores it.
  def fetch(_goth_name), do: Goth.fetch(MyApp.Goth)
end

The function is invoked as apply(module, function, [goth_name | args]) and must return {:ok, %{token: access_token}} or {:error, reason}. It runs on the send path, so keep it cheap (Goth caches; do the same). PushX guards the call: a fetcher that raises, exits, or returns {:error, _} is reported as a retryable :connection_error; one that returns any other shape as :auth_error. Neither escapes as an exception.

When a fetcher is set, PushX starts no PushX.Goth process and :fcm_credentials becomes optional. This option applies to the static configuration only: named FCM instances (PushX.Instance) authenticate with their own :credentials, or their own per-instance :token_fetcher config key — a global fetcher never silently takes over a tenant's OAuth. The test suite uses this seam to exercise the real FCM send path without Google.

finch_name()

@spec finch_name() :: atom()

Gets the Finch pool name.

finch_pool_count()

@spec finch_pool_count() :: pos_integer()

Gets the Finch pool count (number of connection pools).

Default: 2 (increased from 1 in v0.6.0 to handle traffic bursts better)

finch_pool_size()

@spec finch_pool_size() :: pos_integer()

Gets the Finch pool size (connections per pool).

Default: 25 (increased from 10 in v0.6.0 to handle traffic bursts better)

finch_request_opts()

@spec finch_request_opts() :: keyword()

Returns the Finch request options with configured timeouts.

get(key, default \\ nil)

@spec get(atom(), any()) :: any()

Gets a configuration value.

get!(key)

@spec get!(atom()) :: any()

Gets a required configuration value. Raises if the value is not configured.

on_invalid_token()

@spec on_invalid_token() :: {module(), atom(), list()} | nil

Gets the callback for invalid token cleanup.

When set, this MFA tuple is called asynchronously whenever a push returns :invalid_token, :expired_token, or :unregistered.

The callback receives (provider, token, ...extra_args).

Example

config :pushx,
  on_invalid_token: {MyApp.Push, :handle_invalid_token, []}

pool_timeout()

@spec pool_timeout() :: pos_integer()

Gets the pool timeout (time to wait for a connection from pool) in milliseconds. Default: 5 seconds.

receive_timeout()

@spec receive_timeout() :: pos_integer()

Gets the receive timeout (time to wait for response data) in milliseconds. Default: 15 seconds.

request_timeout()

This function is deprecated. Not used by Finch. Use receive_timeout/0 and pool_timeout/0 instead..
@spec request_timeout() :: pos_integer()

Gets the overall request timeout in milliseconds. Default: 30 seconds.

Note: This value is not currently passed to Finch requests. Use :receive_timeout and :pool_timeout instead.

retry_base_delay_ms()

@spec retry_base_delay_ms() :: pos_integer()

Gets the base delay for exponential backoff in milliseconds. Default: 10 seconds (Google's recommended minimum).

retry_enabled?()

@spec retry_enabled?() :: boolean()

Checks if retry is enabled.

retry_max_attempts()

@spec retry_max_attempts() :: pos_integer()

Gets the maximum number of retry attempts.

retry_max_delay_ms()

@spec retry_max_delay_ms() :: pos_integer()

Gets the maximum delay for exponential backoff in milliseconds. Default: 60 seconds.