Current section
Files
Jump to
Current section
Files
lib/phoenix/session_process/helpers.ex
defmodule Phoenix.SessionProcess.Helpers do
@moduledoc """
Helper functions for common session management tasks.
This module provides convenient functions for batch operations,
session health checks, and common patterns.
"""
alias Phoenix.SessionProcess
@doc """
Start sessions for multiple session IDs in parallel.
## Examples
iex> Phoenix.SessionProcess.Helpers.start_sessions(["session1", "session2"])
[{"session1", {:ok, #PID<0.123.0>}}, {"session2", {:ok, #PID<0.124.0>}}]
"""
@spec start_sessions([binary()]) :: [{binary(), {:ok, pid()} | {:error, term()}}]
def start_sessions(session_ids) when is_list(session_ids) do
session_ids
|> Enum.map(fn session_id ->
Task.async(fn -> {session_id, SessionProcess.start(session_id)} end)
end)
|> Task.await_many(5_000)
end
@doc """
Terminate multiple sessions in parallel.
## Examples
iex> Phoenix.SessionProcess.Helpers.terminate_sessions(["session1", "session2"])
[{"session1", :ok}, {"session2", {:error, :not_found}}]
"""
@spec terminate_sessions([binary()]) :: [{binary(), :ok | {:error, term()}}]
def terminate_sessions(session_ids) when is_list(session_ids) do
session_ids
|> Enum.map(fn session_id ->
Task.async(fn -> {session_id, SessionProcess.terminate(session_id)} end)
end)
|> Task.await_many(5_000)
end
@doc """
Broadcast a message to all active sessions.
## Examples
iex> Phoenix.SessionProcess.Helpers.broadcast_all({:system_message, "Maintenance in 5 minutes"})
:ok
"""
@spec broadcast_all(any()) :: :ok
def broadcast_all(message) do
SessionProcess.list_session()
|> Enum.each(fn {session_id, _pid} ->
SessionProcess.cast(session_id, message)
end)
:ok
end
@doc """
Get health status for all sessions.
## Examples
iex> Phoenix.SessionProcess.Helpers.session_health()
%{healthy: 10, crashed: 0, total: 10}
"""
@spec session_health() :: %{healthy: integer(), crashed: integer(), total: integer()}
def session_health() do
sessions = SessionProcess.list_session()
{healthy, crashed} =
sessions
|> Enum.reduce({0, 0}, fn {_session_id, pid}, {h, c} ->
case Process.alive?(pid) do
true -> {h + 1, c}
false -> {h, c + 1}
end
end)
%{
healthy: healthy,
crashed: crashed,
total: length(sessions)
}
end
@doc """
Find sessions by pattern matching on session ID.
## Examples
iex> Phoenix.SessionProcess.Helpers.find_sessions_by_pattern(~r/user_.*/)
["user_123", "user_456"]
"""
@spec find_sessions_by_pattern(Regex.t()) :: [binary()]
def find_sessions_by_pattern(pattern) when is_struct(pattern, Regex) do
SessionProcess.list_session()
|> Enum.map(fn {session_id, _pid} -> session_id end)
|> Enum.filter(fn session_id -> String.match?(session_id, pattern) end)
end
@doc """
Safely call a session with automatic retry on timeout.
## Examples
iex> Phoenix.SessionProcess.Helpers.safe_call("session_123", :get_user, 3)
{:ok, %User{}}
"""
@spec safe_call(binary(), any(), integer(), non_neg_integer()) ::
{:ok, any()} | {:error, term()}
def safe_call(session_id, request, retries \\ 3, timeout \\ 5_000) do
do_safe_call(session_id, request, retries, timeout)
end
defp do_safe_call(_session_id, _request, 0, _timeout) do
{:error, :max_retries_exceeded}
end
defp do_safe_call(session_id, request, retries, timeout) do
case SessionProcess.call(session_id, request, timeout) do
{:ok, result} ->
{:ok, result}
{:error, {:timeout, _}} ->
Process.sleep(100)
do_safe_call(session_id, request, retries - 1, timeout)
{:error, reason} ->
{:error, reason}
end
end
@doc """
Create a session with automatic retry on rate limit.
## Examples
iex> Phoenix.SessionProcess.Helpers.create_session_with_retry("session_123")
{:ok, #PID<0.123.0>}
"""
@spec create_session_with_retry(binary(), module() | nil, any() | nil, integer()) ::
{:ok, pid()} | {:error, term()}
def create_session_with_retry(session_id, module \\ nil, arg \\ nil, retries \\ 5) do
do_create_session_with_retry(session_id, module, arg, retries)
end
defp do_create_session_with_retry(_session_id, _module, _arg, 0) do
{:error, :max_retries_exceeded}
end
defp do_create_session_with_retry(session_id, module, arg, retries) do
result =
if module do
if arg do
SessionProcess.start(session_id, module, arg)
else
SessionProcess.start(session_id, module)
end
else
SessionProcess.start(session_id)
end
case result do
{:ok, pid} ->
{:ok, pid}
{:error, {:session_limit_reached, _max}} ->
Process.sleep(200)
do_create_session_with_retry(session_id, module, arg, retries - 1)
{:error, reason} ->
{:error, reason}
end
end
end