Skip to content

Commit 17f967e

Browse files
committed
refactor: simplify start_session API to 2 arities with keyword options
Simplified start_session from 3 arities to 2 arities using keyword options for a cleaner, more flexible API. Changes: - start_session/2 now accepts keyword options: module:, args: - Removed start_session/3 - Updated deprecation functions to use new options format - Updated all test files to use new API - Updated helpers to build keyword options dynamically Examples: start_session(id, module: Mod, args: args) start_session(id, args: %{user_id: 123}) Breaking: start_session/3 removed (use start_session/2 with options) All 148 tests pass.
1 parent 7f9dd97 commit 17f967e

File tree

7 files changed

+99
-105
lines changed

7 files changed

+99
-105
lines changed

README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -595,10 +595,6 @@ mix run bench/session_benchmark.exs
595595

596596
See `bench/README.md` for detailed benchmarking guide and customization options.
597597

598-
## Contributing
599-
600-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
601-
602598
### Development Setup
603599

604600
1. Fork the repository

lib/phoenix/session_process.ex

Lines changed: 47 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -231,23 +231,15 @@ defmodule Phoenix.SessionProcess do
231231
defdelegate start_session(session_id), to: Phoenix.SessionProcess.ProcessSupervisor
232232

233233
@doc """
234-
Deprecated: Use `start_session/1` instead.
234+
Starts a session process with options.
235235
236-
This function is kept for backward compatibility but will be removed in a future version.
237-
"""
238-
@deprecated "Use start_session/1 instead"
239-
@spec start(binary()) :: {:ok, pid()} | {:error, term()}
240-
def start(session_id), do: start_session(session_id)
241-
242-
@doc """
243-
Starts a session process using a custom module.
244-
245-
This allows you to use a specific session process implementation instead of
246-
the default configured module.
236+
This allows you to customize the module and initialization arguments.
247237
248238
## Parameters
249239
- `session_id` - Unique binary identifier for the session
250-
- `module` - Module implementing the session process behavior
240+
- `opts` - Keyword list of options:
241+
- `:module` - Module implementing the session process behavior (defaults to configured module)
242+
- `:args` - Initialization arguments passed to `init/1` (defaults to nil)
251243
252244
## Returns
253245
- `{:ok, pid}` - Session process started successfully
@@ -257,71 +249,69 @@ defmodule Phoenix.SessionProcess do
257249
258250
## Examples
259251
260-
{:ok, pid} = Phoenix.SessionProcess.start_session("user_123", MyApp.CustomSessionProcess)
252+
# Use default module
253+
{:ok, pid} = Phoenix.SessionProcess.start_session("user_123")
254+
255+
# Use custom module
256+
{:ok, pid} = Phoenix.SessionProcess.start_session("user_123", module: MyApp.CustomSessionProcess)
261257
262-
iex> result = Phoenix.SessionProcess.start_session("valid_session", Phoenix.SessionProcess.DefaultSessionProcess)
258+
# Use custom module with initialization arguments
259+
{:ok, pid} = Phoenix.SessionProcess.start_session("user_123",
260+
module: MyApp.SessionProcess,
261+
args: %{user_id: 123})
262+
263+
# Use default module with initialization arguments
264+
{:ok, pid} = Phoenix.SessionProcess.start_session("user_456", args: [debug: true])
265+
266+
iex> result = Phoenix.SessionProcess.start_session("valid_session", module: Phoenix.SessionProcess.DefaultSessionProcess)
263267
iex> match?({:ok, _pid}, result) or match?({:error, {:already_started, _pid}}, result)
264268
true
265269
266-
iex> Phoenix.SessionProcess.start_session("invalid@session", Phoenix.SessionProcess.DefaultSessionProcess)
267-
{:error, {:invalid_session_id, "invalid@session"}}
270+
iex> result = Phoenix.SessionProcess.start_session("valid_with_args", module: Phoenix.SessionProcess.DefaultSessionProcess, args: %{user_id: 123})
271+
iex> match?({:ok, _pid}, result) or match?({:error, {:already_started, _pid}}, result)
272+
true
268273
"""
269-
@spec start_session(binary(), atom()) :: {:ok, pid()} | {:error, term()}
270-
defdelegate start_session(session_id, module), to: Phoenix.SessionProcess.ProcessSupervisor
274+
@spec start_session(binary(), keyword()) :: {:ok, pid()} | {:error, term()}
275+
defdelegate start_session(session_id, opts), to: Phoenix.SessionProcess.ProcessSupervisor
271276

272277
@doc """
273-
Deprecated: Use `start_session/2` instead.
278+
Deprecated: Use `start_session/1` instead.
274279
275280
This function is kept for backward compatibility but will be removed in a future version.
276281
"""
277-
@deprecated "Use start_session/2 instead"
278-
@spec start(binary(), atom()) :: {:ok, pid()} | {:error, term()}
279-
def start(session_id, module), do: start_session(session_id, module)
282+
@deprecated "Use start_session/1 instead"
283+
@spec start(binary()) :: {:ok, pid()} | {:error, term()}
284+
def start(session_id), do: start_session(session_id)
280285

281286
@doc """
282-
Starts a session process with a custom module and initialization arguments.
287+
Deprecated: Use `start_session/2` with options instead.
283288
284-
The initialization arguments are passed to the module's `init/1` callback,
285-
allowing you to set up initial state or configuration.
289+
## Migration
286290
287-
## Parameters
288-
- `session_id` - Unique binary identifier for the session
289-
- `module` - Module implementing the session process behavior
290-
- `arg` - Initialization argument(s) passed to `init/1`
291-
292-
## Returns
293-
- `{:ok, pid}` - Session process started successfully
294-
- `{:error, {:already_started, pid}}` - Session already exists
295-
- `{:error, {:invalid_session_id, id}}` - Invalid session ID format
296-
- `{:error, {:session_limit_reached, max}}` - Maximum sessions exceeded
297-
298-
## Examples
299-
300-
# With map argument
301-
{:ok, pid} = Phoenix.SessionProcess.start_session("user_123", MyApp.SessionProcess, %{user_id: 123})
291+
# Old
292+
start(session_id, MyModule)
302293
303-
# With keyword list
304-
{:ok, pid} = Phoenix.SessionProcess.start_session("user_456", MyApp.SessionProcess, [debug: true])
305-
306-
iex> result = Phoenix.SessionProcess.start_session("valid_session_with_args", Phoenix.SessionProcess.DefaultSessionProcess, %{user_id: 123})
307-
iex> match?({:ok, _pid}, result) or match?({:error, {:already_started, _pid}}, result)
308-
true
309-
310-
iex> result = Phoenix.SessionProcess.start_session("valid_session_with_list", Phoenix.SessionProcess.DefaultSessionProcess, [debug: true])
311-
iex> match?({:ok, _pid}, result) or match?({:error, {:already_started, _pid}}, result)
312-
true
294+
# New
295+
start_session(session_id, module: MyModule)
313296
"""
314-
@spec start_session(binary(), atom(), any()) :: {:ok, pid()} | {:error, term()}
315-
defdelegate start_session(session_id, module, arg), to: Phoenix.SessionProcess.ProcessSupervisor
297+
@deprecated "Use start_session/2 with module: option instead"
298+
@spec start(binary(), atom()) :: {:ok, pid()} | {:error, term()}
299+
def start(session_id, module), do: start_session(session_id, module: module)
316300

317301
@doc """
318-
Deprecated: Use `start_session/3` instead.
302+
Deprecated: Use `start_session/2` with options instead.
319303
320-
This function is kept for backward compatibility but will be removed in a future version.
304+
## Migration
305+
306+
# Old
307+
start(session_id, MyModule, args)
308+
309+
# New
310+
start_session(session_id, module: MyModule, args: args)
321311
"""
322-
@deprecated "Use start_session/3 instead"
312+
@deprecated "Use start_session/2 with module: and args: options instead"
323313
@spec start(binary(), atom(), any()) :: {:ok, pid()} | {:error, term()}
324-
def start(session_id, module, arg), do: start_session(session_id, module, arg)
314+
def start(session_id, module, arg), do: start_session(session_id, module: module, args: arg)
325315

326316
@doc """
327317
Checks if a session process is currently running.

lib/phoenix/session_process/helpers.ex

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,15 +156,18 @@ defmodule Phoenix.SessionProcess.Helpers do
156156
end
157157

158158
defp do_create_session_with_retry(session_id, module, arg, retries) do
159+
# Build options for start_session/2
160+
opts =
161+
[]
162+
|> Keyword.put_new_lazy(:module, fn -> module end)
163+
|> Keyword.put_new_lazy(:args, fn -> arg end)
164+
|> Enum.reject(fn {_k, v} -> is_nil(v) end)
165+
159166
result =
160-
if module do
161-
if arg do
162-
SessionProcess.start_session(session_id, module, arg)
163-
else
164-
SessionProcess.start_session(session_id, module)
165-
end
166-
else
167+
if opts == [] do
167168
SessionProcess.start_session(session_id)
169+
else
170+
SessionProcess.start_session(session_id, opts)
168171
end
169172

170173
case result do

lib/phoenix/session_process/process_superviser.ex

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -181,38 +181,43 @@ defmodule Phoenix.SessionProcess.ProcessSupervisor do
181181
end
182182

183183
@doc """
184-
Starts a session process using a specific module.
184+
Starts a session process with options.
185185
186186
## Parameters
187187
188188
- `session_id` - Unique identifier for the session
189-
- `module` - Session process module to use
189+
- `opts` - Keyword list of options:
190+
- `:module` - Session process module to use (defaults to configured module)
191+
- `:args` - Initialization arguments passed to `init/1` (defaults to nil)
190192
191193
## Returns
192194
193195
- `{:ok, pid()}` - Session process started successfully
194196
- `{:error, reason}` - Failed to start session process
195-
"""
196-
def start_session(session_id, module) do
197-
start_session_with_module(session_id, module)
198-
end
199197
200-
@doc """
201-
Starts a session process using a specific module with initialization arguments.
198+
## Examples
202199
203-
## Parameters
200+
# Use default module with no args
201+
start_session("session_123")
204202
205-
- `session_id` - Unique identifier for the session
206-
- `module` - Session process module to use
207-
- `arg` - Initialization arguments for the session process
203+
# Use custom module with default args
204+
start_session("session_123", module: MyApp.SessionProcess)
208205
209-
## Returns
206+
# Use custom module with custom args
207+
start_session("session_123", module: MyApp.SessionProcess, args: %{user_id: 123})
210208
211-
- `{:ok, pid()}` - Session process started successfully
212-
- `{:error, reason}` - Failed to start session process
209+
# Use default module with custom args
210+
start_session("session_123", args: %{user_id: 123})
213211
"""
214-
def start_session(session_id, module, arg) do
215-
start_session_with_module(session_id, module, arg)
212+
def start_session(session_id, opts) when is_list(opts) do
213+
module = Keyword.get(opts, :module, Config.session_process())
214+
args = Keyword.get(opts, :args)
215+
start_session_with_module(session_id, module, args)
216+
end
217+
218+
# Backward compatibility for old 2-arity call with module atom
219+
def start_session(session_id, module) when is_atom(module) do
220+
start_session_with_module(session_id, module)
216221
end
217222

218223
@doc """

test/phoenix/session_process/integration_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ defmodule Phoenix.SessionProcess.IntegrationTest do
4646

4747
# Start with custom module
4848
assert {:ok, _pid} =
49-
SessionProcess.start_session(session_id, TestCustomSession, %{test: "data"})
49+
SessionProcess.start_session(session_id, module: TestCustomSession, args: %{test: "data"})
5050

5151
# Verify custom initialization worked
5252
assert %{custom: true} = SessionProcess.call(session_id, :get_state)

test/phoenix/session_process/macro_consistency_test.exs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ defmodule Phoenix.SessionProcess.MacroConsistencyTest do
3232
session_id = "test_process_with_arg_#{:rand.uniform(10000)}"
3333
init_arg = %{user_id: 123, data: "test"}
3434

35-
{:ok, _pid} = SessionProcess.start_session(session_id, TestProcessWithArg, init_arg)
35+
{:ok, _pid} = SessionProcess.start_session(session_id, module: TestProcessWithArg, args: init_arg)
3636

3737
state = SessionProcess.call(session_id, :get_state)
3838
assert state.initialized_with == init_arg
@@ -44,7 +44,7 @@ defmodule Phoenix.SessionProcess.MacroConsistencyTest do
4444
session_id = "test_process_with_arg_#{:rand.uniform(10000)}"
4545
init_arg = %{user_id: 456, data: "test"}
4646

47-
{:ok, _pid} = SessionProcess.start_session(session_id, TestProcessLinkWithArg, init_arg)
47+
{:ok, _pid} = SessionProcess.start_session(session_id, module: TestProcessLinkWithArg, args: init_arg)
4848

4949
state = SessionProcess.call(session_id, :get_state)
5050
assert state.initialized_with == init_arg
@@ -61,8 +61,8 @@ defmodule Phoenix.SessionProcess.MacroConsistencyTest do
6161
init_arg = %{value: 42}
6262

6363
# Both should accept the same argument format
64-
{:ok, _} = SessionProcess.start_session(session_id_1, TestProcessWithArg, init_arg)
65-
{:ok, _} = SessionProcess.start_session(session_id_2, TestProcessLinkWithArg, init_arg)
64+
{:ok, _} = SessionProcess.start_session(session_id_1, module: TestProcessWithArg, args: init_arg)
65+
{:ok, _} = SessionProcess.start_session(session_id_2, module: TestProcessLinkWithArg, args: init_arg)
6666

6767
state1 = SessionProcess.call(session_id_1, :get_state)
6868
state2 = SessionProcess.call(session_id_2, :get_state)

test/phoenix/session_process_test.exs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,28 @@ defmodule Phoenix.SessionProcessTest do
2828
test "test start session process" do
2929
session_id = SessionId.generate_unique_session_id()
3030
assert SessionProcess.started?(session_id) == false
31-
{:ok, pid} = SessionProcess.start_session(session_id, TestProcess, %{value: 0})
31+
{:ok, pid} = SessionProcess.start_session(session_id, module: TestProcess, args: %{value: 0})
3232
assert is_pid(pid)
3333
assert SessionProcess.started?(session_id) == true
3434
end
3535

3636
test "test terminate session process" do
3737
session_id = SessionId.generate_unique_session_id()
38-
{:ok, _pid} = SessionProcess.start_session(session_id, TestProcess, %{value: 0})
38+
{:ok, _pid} = SessionProcess.start_session(session_id, module: TestProcess, args: %{value: 0})
3939
assert SessionProcess.started?(session_id) == true
4040
SessionProcess.terminate(session_id)
4141
assert SessionProcess.started?(session_id) == false
4242
end
4343

4444
test "test call on session process" do
4545
session_id = SessionId.generate_unique_session_id()
46-
{:ok, _pid} = SessionProcess.start_session(session_id, TestProcess, %{value: 123})
46+
{:ok, _pid} = SessionProcess.start_session(session_id, module: TestProcess, args: %{value: 123})
4747
assert SessionProcess.call(session_id, :get_value) == 123
4848
end
4949

5050
test "test cast on session process" do
5151
session_id = SessionId.generate_unique_session_id()
52-
{:ok, _pid} = SessionProcess.start_session(session_id, TestProcess, %{value: 0})
52+
{:ok, _pid} = SessionProcess.start_session(session_id, module: TestProcess, args: %{value: 0})
5353
assert SessionProcess.call(session_id, :get_value) == 0
5454
SessionProcess.cast(session_id, :add_one)
5555
assert SessionProcess.call(session_id, :get_value) == 1
@@ -64,8 +64,8 @@ defmodule Phoenix.SessionProcessTest do
6464
session_id1 = SessionId.generate_unique_session_id()
6565
session_id2 = SessionId.generate_unique_session_id()
6666

67-
{:ok, pid1} = SessionProcess.start_session(session_id1, TestProcess, %{value: 1})
68-
{:ok, pid2} = SessionProcess.start_session(session_id2, TestProcess, %{value: 2})
67+
{:ok, pid1} = SessionProcess.start_session(session_id1, module: TestProcess, args: %{value: 1})
68+
{:ok, pid2} = SessionProcess.start_session(session_id2, module: TestProcess, args: %{value: 2})
6969

7070
sessions = SessionProcess.list_session()
7171
# Check that our created sessions are in the list
@@ -79,7 +79,7 @@ defmodule Phoenix.SessionProcessTest do
7979

8080
test "removes session when terminated" do
8181
session_id = SessionId.generate_unique_session_id()
82-
{:ok, pid} = SessionProcess.start_session(session_id, TestProcess, %{value: 0})
82+
{:ok, pid} = SessionProcess.start_session(session_id, module: TestProcess, args: %{value: 0})
8383

8484
# Check session exists in list
8585
sessions_before = SessionProcess.list_session()
@@ -101,8 +101,8 @@ defmodule Phoenix.SessionProcessTest do
101101
session_id1 = SessionId.generate_unique_session_id()
102102
session_id2 = SessionId.generate_unique_session_id()
103103

104-
{:ok, _pid1} = SessionProcess.start_session(session_id1, TestProcess, %{value: 1})
105-
{:ok, _pid2} = SessionProcess.start_session(session_id2, TestProcess, %{value: 2})
104+
{:ok, _pid1} = SessionProcess.start_session(session_id1, module: TestProcess, args: %{value: 1})
105+
{:ok, _pid2} = SessionProcess.start_session(session_id2, module: TestProcess, args: %{value: 2})
106106

107107
sessions = SessionProcess.list_sessions_by_module(TestProcess)
108108
# Check that our created sessions are in the list
@@ -118,10 +118,10 @@ defmodule Phoenix.SessionProcessTest do
118118
session_id1 = SessionId.generate_unique_session_id()
119119
session_id2 = SessionId.generate_unique_session_id()
120120

121-
{:ok, _pid1} = SessionProcess.start_session(session_id1, TestProcess, %{value: 1})
121+
{:ok, _pid1} = SessionProcess.start_session(session_id1, module: TestProcess, args: %{value: 1})
122122

123123
{:ok, _pid2} =
124-
SessionProcess.start_session(session_id2, TestProcessLink, %{value: 2})
124+
SessionProcess.start_session(session_id2, module: TestProcessLink, args: %{value: 2})
125125

126126
test_sessions = SessionProcess.list_sessions_by_module(TestProcess)
127127
link_sessions = SessionProcess.list_sessions_by_module(TestProcessLink)
@@ -152,10 +152,10 @@ defmodule Phoenix.SessionProcessTest do
152152
session_id1 = SessionId.generate_unique_session_id()
153153
session_id2 = SessionId.generate_unique_session_id()
154154

155-
{:ok, _pid1} = SessionProcess.start_session(session_id1, TestProcess, %{value: 1})
155+
{:ok, _pid1} = SessionProcess.start_session(session_id1, module: TestProcess, args: %{value: 1})
156156

157157
{:ok, _pid2} =
158-
SessionProcess.start_session(session_id2, TestProcessLink, %{value: 2})
158+
SessionProcess.start_session(session_id2, module: TestProcessLink, args: %{value: 2})
159159

160160
info = SessionProcess.session_info()
161161
# Check that both modules are in the list
@@ -173,7 +173,7 @@ defmodule Phoenix.SessionProcessTest do
173173
describe "get_session_id/0 in :process macro" do
174174
test "returns correct session_id from within session process" do
175175
session_id = SessionId.generate_unique_session_id()
176-
{:ok, _pid} = SessionProcess.start_session(session_id, TestProcess, %{value: 0})
176+
{:ok, _pid} = SessionProcess.start_session(session_id, module: TestProcess, args: %{value: 0})
177177

178178
# Call a function that uses get_session_id internally
179179
result = SessionProcess.call(session_id, :get_my_session_id)
@@ -184,7 +184,7 @@ defmodule Phoenix.SessionProcessTest do
184184
describe "get_session_id/0 with LiveView monitoring" do
185185
test "returns correct session_id from within session process" do
186186
session_id = SessionId.generate_unique_session_id()
187-
{:ok, _pid} = SessionProcess.start_session(session_id, TestProcessLink, %{value: 0})
187+
{:ok, _pid} = SessionProcess.start_session(session_id, module: TestProcessLink, args: %{value: 0})
188188

189189
result = SessionProcess.call(session_id, :get_my_session_id)
190190
assert result == session_id

0 commit comments

Comments
 (0)