Packages
phoenix_session_process
1.0.0-rc.0
Session isolation and state management for Phoenix applications
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
alias Phoenix.SessionProcess.Config
alias Phoenix.SessionProcess.Registry, as: SessionRegistry
@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
@doc """
Gets the session module for a given process PID.
"""
@spec get_session_module(pid()) :: module()
def get_session_module(pid) do
case Registry.lookup(SessionRegistry, pid) do
[{_, module}] -> module
_ -> Config.session_process()
end
end
end