Phoenix. SessionProcess. DefaultSessionProcess
(phoenix_session_process v1.0.1)
Copy Markdown
View Source
Default session process implementation providing basic key-value storage.
This module serves as the default session process when no custom session module is specified. It provides a simple key-value store interface that can be used for basic session state management without requiring custom implementation.
Features
Simple Key-Value Storage
- Store any Elixir term with a binary key
- Retrieve values by key
- Delete keys from the session state
- Support for complex data structures
Process Communication
call/2operations for synchronous requestscast/2operations for asynchronous updates- Echo and ping functionality for testing
Public API
Call Operations
:ping- Returns:pong(useful for health checks):get_state- Returns the application state (handled by macro){:sleep, duration}- Sleeps for specified milliseconds (testing)- Any other request - Echoes the request back
Cast Operations
{:put, key, value}- Stores a value with the given key{:delete, key}- Removes the key from the session state- Any other cast - No-op (ignored)
Usage Examples
Basic Operations
# Store data in session
Phoenix.SessionProcess.cast(session_id, {:put, :user_id, 123})
Phoenix.SessionProcess.cast(session_id, {:put, :preferences, %{theme: :dark}})
# Retrieve session state
state = Phoenix.SessionProcess.get_state(session_id)
# => %{user_id: 123, preferences: %{theme: :dark}}
# Delete data from session
Phoenix.SessionProcess.cast(session_id, {:delete, :user_id})Health Check
# Check if session process is responsive
:pong = Phoenix.SessionProcess.call(session_id, :ping)Testing
# Simulate slow operations
:ok = Phoenix.SessionProcess.call(session_id, {:sleep, 1000})Default Session Module
This module is used automatically when no custom session module is specified in the configuration:
# Uses DefaultSessionProcess
Phoenix.SessionProcess.start("session_123")
# Uses custom module
Phoenix.SessionProcess.start("session_123", MyApp.CustomSessionProcess)Limitations
- Simple key-value storage (no complex queries)
- No data validation or type checking
- No persistence across application restarts
- No built-in security or access controls
Custom Implementation with Redux Store API (v1.0.0)
For more advanced use cases, create a custom session process using the Redux Store API
with the :reducer macro:
defmodule MyApp.CartReducer do
use Phoenix.SessionProcess, :reducer
@name :cart
@action_prefix "cart"
def init_state do
%{items: [], total: 0}
end
def handle_action(action, state) do
alias Phoenix.SessionProcess.Action
case action do
%Action{type: "cart.add", payload: item} ->
%{state | items: [item | state.items], total: state.total + item.price}
%Action{type: "cart.clear"} ->
%{state | items: [], total: 0}
_ ->
state
end
end
end
defmodule MyApp.SessionProcess do
use Phoenix.SessionProcess, :process
def init_state(_args) do
%{}
end
def combined_reducers do
[MyApp.CartReducer]
end
endUse the session process:
# Start session
Phoenix.SessionProcess.start(session_id, MyApp.SessionProcess)
# Dispatch actions (MUST use binary types)
:ok = Phoenix.SessionProcess.dispatch(session_id, "cart.add", %{id: 1, price: 10})
:ok = Phoenix.SessionProcess.dispatch(session_id, "cart.add", %{id: 2, price: 20})
# Get current state (namespaced by reducer)
state = Phoenix.SessionProcess.get_state(session_id)
# => %{cart: %{items: [...], total: 30}}Configure it as the default:
config :phoenix_session_process,
session_process: MyApp.SessionProcess
Summary
Functions
Returns a specification to start this module under a supervisor.
Define combined reducers for state slicing.
Initialize session process state with Redux infrastructure.
Initialize your application's state.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
Define combined reducers for state slicing.
Override this callback to return a list of reducer modules or tuples. Each reducer module manages its own portion of the state.
Examples
def combined_reducers() do
[
MyApp.Reducers.UserReducer, # Uses module's @name and @action_prefix
{:cart, MyApp.Reducers.CartReducer}, # Custom name, action_prefix = "cart"
{:shipping, MyApp.Reducers.ShippingReducer, "ship"} # Custom name and action_prefix
]
endList Formats
The list can contain three formats:
Module atom - Uses the reducer's
@nameand@action_prefixattributes:UserReducer→ name from@name, action_prefix from@action_prefix(defaults to stringified@name)
{name, Module} tuple - Custom name, action_prefix defaults to stringified name:
{:cart, CartReducer}→ name =:cart, action_prefix ="cart"
{name, Module, action_prefix} tuple - Explicit name and action_prefix:
{:shipping, ShippingReducer, "ship"}→ name =:shipping, action_prefix ="ship"
State Slicing
Each reducer receives only its slice of state based on the name:
- UserReducer receives
state.users(if @name is :users) - CartReducer receives
state.cart(from {:cart, CartReducer}) - ShippingReducer receives
state.shipping(from {:shipping, ...})
Action Routing
Actions are routed to reducers based on their @action_prefix attribute:
"user.reload"→ Routes to reducer with action_prefix"user""cart.add"→ Routes to reducer with action_prefix"cart""ship.calculate"→ Routes to reducer with action_prefix"ship"
You can also explicitly target reducers in dispatch:
dispatch(session_id, "reload", reducers: [:user, :cart])
Initialize session process state with Redux infrastructure.
Override init_state/1 to provide your application's initial state.
Initialize your application's state.
Override this callback to provide your initial state as a map.
Examples
def init_state(_arg) do
%{count: 0, user: nil, items: []}
end
def init_state(user_id) do
%{user_id: user_id, cart: [], preferences: %{}}
end