Packages
phoenix_kit
1.7.143
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit/workers/oauth_config_loader.ex
defmodule PhoenixKit.Workers.OAuthConfigLoader do
@moduledoc """
GenServer worker that ensures OAuth configuration is loaded from database
before any OAuth requests are processed.
This worker runs synchronously during application startup to configure
OAuth providers from database settings.
## Startup Sequence
1. PhoenixKit.Cache starts with sync_init, loading critical OAuth settings
2. OAuthConfigLoader starts, OAuth settings already in cache
3. Loads OAuth configuration from cache
4. Configures Ueberauth with available providers
5. Returns :ok when complete
## Why This Is Needed
Parent applications typically start services in this order:
- Repo (database ready)
- PubSub
- Parent Endpoint (router compiles, Ueberauth.init() runs)
- PhoenixKit.Supervisor (OAuth config should load here)
With sync_init enabled in the Cache, critical OAuth settings are loaded
synchronously before this worker starts, eliminating race conditions.
This worker ensures OAuth configuration is available as early as possible
during PhoenixKit.Supervisor initialization.
"""
use GenServer
require Logger
alias PhoenixKit.Config.EndpointUrlSync
alias PhoenixKit.Users.OAuthConfig
## Client API
@doc """
Starts the OAuth configuration loader.
Loads OAuth configuration from cache which is pre-warmed with critical settings.
"""
def start_link(_opts) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
@doc """
Gets the current status of OAuth configuration.
Returns:
- `{:ok, :loaded}` - Configuration successfully loaded
- `{:ok, :not_loaded, reason}` - Configuration not loaded with reason
- `{:error, :not_running}` - OAuthConfigLoader is not running
"""
def get_status do
case Process.whereis(__MODULE__) do
nil ->
{:error, :not_running}
pid ->
try do
state = GenServer.call(pid, :get_status, 5000)
case state do
%{status: :loaded} ->
{:ok, :loaded}
%{status: :not_loaded, reason: reason} ->
{:ok, :not_loaded, reason}
%{status: :error, error: error} ->
{:ok, :error, error}
_ ->
{:ok, :unknown}
end
catch
:exit, _ ->
{:error, :timeout}
end
end
end
@doc """
Attempts to reload OAuth configuration.
This can be called to retry loading configuration if it failed during startup.
"""
def reload_config do
case Process.whereis(__MODULE__) do
nil ->
{:error, :not_running}
pid ->
GenServer.call(pid, :reload_config, 10_000)
end
end
## Server Callbacks
@impl true
def init(_) do
# Sync site_url to Endpoint config before loading OAuth
EndpointUrlSync.sync()
# Load OAuth configuration synchronously during initialization
# With sync_init in the Cache, critical OAuth settings are already loaded
case load_oauth_config() do
:ok ->
Logger.info("OAuth config loaded successfully during startup")
{:ok, %{status: :loaded}}
{:error, :modules_not_loaded} ->
Logger.info("OAuth modules not loaded, OAuth features will be unavailable")
{:ok, %{status: :not_loaded, reason: :modules_not_loaded}}
{:error, :repo_not_available} ->
# During Mix tasks, the repo may not be available
# This is expected and not an error condition
Logger.debug(
"OAuth config loading skipped: Repository not available (likely during Mix task execution)"
)
{:ok, %{status: :not_loaded, reason: :repo_not_available}}
end
rescue
# Catch unexpected errors during initialization
error ->
Logger.error("""
Critical error during OAuth config loader initialization:
#{Exception.format(:error, error, __STACKTRACE__)}
OAuth features will be unavailable.
""")
# Still don't crash supervisor, but log the error prominently
{:ok, %{status: :error, error: error}}
end
@impl true
def handle_call(:get_status, _from, state) do
{:reply, state, state}
end
def handle_call(:reload_config, _from, state) do
case load_oauth_config() do
:ok ->
new_state = %{state | status: :loaded}
Logger.info("OAuth configuration reloaded successfully")
{:reply, :ok, new_state}
{:error, reason} = error ->
new_state = %{state | status: :not_loaded, reason: reason}
Logger.warning("OAuth configuration reload failed: #{inspect(reason)}")
{:reply, error, new_state}
end
end
## Private Helpers
defp load_oauth_config do
# Check if required modules are loaded
if Code.ensure_loaded?(PhoenixKit.Users.OAuthConfig) and
Code.ensure_loaded?(PhoenixKit.Settings) do
do_load_oauth_config()
else
Logger.debug("OAuth modules not loaded, skipping configuration")
{:error, :modules_not_loaded}
end
end
defp do_load_oauth_config do
# With sync_init enabled, critical OAuth settings are already in cache
# No need to check cache size or wait for warming
# Check if repository is available (for Mix tasks)
if PhoenixKit.Settings.repo_available?() do
# OAuth settings are already loaded via sync_init
oauth_enabled = PhoenixKit.Settings.get_setting("oauth_enabled", "false")
# Check that at least one provider's credentials are accessible (direct DB read)
has_any_oauth_data =
PhoenixKit.Settings.has_oauth_credentials_direct?(:google) or
PhoenixKit.Settings.has_oauth_credentials_direct?(:apple) or
PhoenixKit.Settings.has_oauth_credentials_direct?(:github) or
PhoenixKit.Settings.has_oauth_credentials_direct?(:facebook)
Logger.debug(
"OAuth configuration: enabled=#{oauth_enabled}, has_oauth_data=#{has_any_oauth_data}"
)
# Configure OAuth providers from settings
OAuthConfig.configure_providers()
:ok
else
{:error, :repo_not_available}
end
rescue
# Database connection errors (includes transient "cached plan" errors during migrations)
error in [DBConnection.ConnectionError, Postgrex.Error] ->
Logger.debug("OAuth config loading skipped: #{Exception.message(error)}")
{:error, :repo_not_available}
# Any other unexpected error
error ->
# Log full error with stacktrace for debugging
Logger.error("""
Unexpected error loading OAuth configuration:
#{Exception.format(:error, error, __STACKTRACE__)}
""")
# Re-raise to fail fast on unexpected errors
reraise error, __STACKTRACE__
end
end