Skip to content

Commit 7e7a8da

Browse files
gsmlgGSMLG-BOT
andauthored
feat: Redux subscriptions, selectors, and critical bug fixes for v0.5.0 (#5)
Co-authored-by: Jonathan Gao <[email protected]>
1 parent f2a0c71 commit 7e7a8da

33 files changed

+5192
-457
lines changed

.github/workflows/ci.yml

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ on:
55
branches: [ '*' ]
66

77
jobs:
8-
test:
9-
name: Build and test
8+
compile:
9+
name: Compile
1010
runs-on: ubuntu-latest
1111

1212
steps:
@@ -31,19 +31,99 @@ jobs:
3131
- name: Install dependencies
3232
run: mix deps.get
3333

34-
- name: Compile
34+
- name: Compile with warnings as errors
3535
run: mix compile --warnings-as-errors
3636

37-
- name: Run Credo
37+
format:
38+
name: Format Check
39+
runs-on: ubuntu-latest
40+
41+
steps:
42+
- name: Checkout code
43+
uses: actions/checkout@v4
44+
45+
- name: Set up Elixir
46+
uses: erlef/setup-beam@v1
47+
with:
48+
elixir-version: '1.18'
49+
otp-version: '28'
50+
51+
- name: Restore dependencies cache
52+
uses: actions/cache@v4
53+
with:
54+
path: |
55+
deps
56+
_build
57+
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
58+
restore-keys: ${{ runner.os }}-mix-
59+
60+
- name: Install dependencies
61+
run: mix deps.get
62+
63+
- name: Check code formatting
64+
run: mix format --check-formatted
65+
66+
credo:
67+
name: Credo
68+
runs-on: ubuntu-latest
69+
70+
steps:
71+
- name: Checkout code
72+
uses: actions/checkout@v4
73+
74+
- name: Set up Elixir
75+
uses: erlef/setup-beam@v1
76+
with:
77+
elixir-version: '1.18'
78+
otp-version: '28'
79+
80+
- name: Restore dependencies cache
81+
uses: actions/cache@v4
82+
with:
83+
path: |
84+
deps
85+
_build
86+
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
87+
restore-keys: ${{ runner.os }}-mix-
88+
89+
- name: Install dependencies
90+
run: mix deps.get
91+
92+
- name: Run Credo strict
3893
run: mix credo --strict
3994

40-
- name: Build Dialyzer PLT (cached)
41-
id: plt
95+
dialyzer:
96+
name: Dialyzer
97+
runs-on: ubuntu-latest
98+
99+
steps:
100+
- name: Checkout code
101+
uses: actions/checkout@v4
102+
103+
- name: Set up Elixir
104+
uses: erlef/setup-beam@v1
105+
with:
106+
elixir-version: '1.18'
107+
otp-version: '28'
108+
109+
- name: Restore dependencies cache
110+
uses: actions/cache@v4
111+
with:
112+
path: |
113+
deps
114+
_build
115+
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
116+
restore-keys: ${{ runner.os }}-mix-
117+
118+
- name: Install dependencies
119+
run: mix deps.get
120+
121+
- name: Restore Dialyzer PLT cache
42122
uses: actions/cache@v4
43123
with:
44124
path: priv/plts
45-
key: dialyzer-${{ hashFiles('mix.lock') }}
125+
key: ${{ runner.os }}-dialyzer-${{ hashFiles('**/mix.lock') }}
126+
restore-keys: ${{ runner.os }}-dialyzer-
46127

47128
- name: Run Dialyzer
48129
run: mix dialyzer --halt-exit-status
49-

.github/workflows/test.yml

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@ name: Test
22

33
on:
44
push:
5-
branches: [ main ]
6-
pull_request:
75
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main ]
88

99
jobs:
1010
test:
11+
name: Test
1112
runs-on: ubuntu-latest
1213

14+
services:
15+
mailhog:
16+
image: mailhog/mailhog:latest
17+
ports:
18+
- 1025:1025
19+
- 8025:8025
20+
1321
steps:
1422
- name: Checkout code
1523
uses: actions/checkout@v5
@@ -20,7 +28,11 @@ jobs:
2028
elixir-version: '1.18'
2129
otp-version: '28'
2230

23-
- name: Cache dependencies
31+
- uses: oven-sh/setup-bun@v2
32+
with:
33+
bun-version: latest
34+
35+
- name: Restore dependencies cache
2436
uses: actions/cache@v4
2537
with:
2638
path: |
@@ -31,10 +43,7 @@ jobs:
3143
${{ runner.os }}-mix-
3244
3345
- name: Install dependencies
34-
run: |
35-
mix local.hex --force
36-
mix local.rebar --force
37-
mix deps.get
46+
run: mix deps.get
3847

3948
- name: Run tests
4049
run: mix test

CLAUDE.md

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,35 @@ This is Phoenix.SessionProcess, an Elixir library that creates a process for eac
1010

1111
### Development Commands
1212
- `mix deps.get` - Install dependencies
13+
- `mix compile` - Compile the project
14+
- `mix compile --warnings-as-errors` - Compile with strict warnings (CI requirement)
1315
- `mix test` - Run all tests
1416
- `mix test test/path/to/specific_test.exs` - Run a specific test file
15-
- `mix compile` - Compile the project
16-
- `mix docs` - Generate documentation
17+
- `mix test test/phoenix/session_process/` - Run all tests in a directory
1718
- `mix format` - Format code
19+
- `mix format --check-formatted` - Check formatting without modifying files (CI requirement)
20+
- `mix credo --strict` - Run static code analysis with strict mode (CI requirement)
21+
- `mix dialyzer` - Run type checking (first run builds PLT cache)
22+
- `mix dialyzer --halt-exit-status` - Run type checking and exit with error code on issues (CI requirement)
23+
- `mix lint` - Run both Credo and Dialyzer (defined in mix.exs aliases)
24+
- `mix docs` - Generate documentation
1825
- `mix hex.publish` - Publish to Hex.pm (requires authentication)
1926

27+
### Code Quality Requirements
28+
Before committing, ensure code passes all CI checks:
29+
1. Compiles without warnings: `mix compile --warnings-as-errors`
30+
2. Properly formatted: `mix format --check-formatted`
31+
3. Passes Credo: `mix credo --strict`
32+
4. Passes Dialyzer: `mix dialyzer --halt-exit-status`
33+
2034
### Testing
21-
The test suite uses ExUnit. Tests are located in the `test/` directory. The test helper (test/test_helper.exs:3) automatically starts the supervisor.
35+
The test suite uses ExUnit. Tests are located in the `test/` directory. The test helper (test/test_helper.exs:3) automatically starts the supervisor and configures the default TestProcess module.
2236

2337
### Development Environment
24-
The project uses `devenv` for development environment setup with Nix. Key configuration:
25-
- Uses Elixir/BEAM 27
26-
- Runs `hello` script on shell entry for greeting
38+
The project uses `devenv` for development environment setup with Nix:
39+
- Elixir 1.18+ with OTP 28+ (minimum: Elixir 1.14, OTP 24)
2740
- Includes git, figlet, and lolcat tools
41+
- Run `devenv shell` to enter the development environment
2842

2943
### Benchmarking
3044
Performance testing available via:
@@ -38,37 +52,76 @@ Expected performance:
3852

3953
## Architecture
4054

55+
### Module Organization
56+
57+
The library is organized into several logical groups:
58+
59+
**Core API** (primary interface for users):
60+
- `Phoenix.SessionProcess` - Main public API
61+
- `Phoenix.SessionProcess.SessionId` - Plug for session ID generation
62+
63+
**Internals** (supervision and lifecycle management):
64+
- `Phoenix.SessionProcess.Supervisor` - Top-level supervisor (Note: filename is `superviser.ex`)
65+
- `Phoenix.SessionProcess.ProcessSupervisor` - Dynamic supervisor for sessions (Note: filename is `process_superviser.ex`)
66+
- `Phoenix.SessionProcess.Cleanup` - TTL-based cleanup
67+
- `Phoenix.SessionProcess.DefaultSessionProcess` - Default session implementation
68+
69+
**State Management Utilities**:
70+
- `Phoenix.SessionProcess.Redux` - Optional Redux-style state with actions/reducers, subscriptions, and selectors (advanced use cases)
71+
- `Phoenix.SessionProcess.Redux.Selector` - Memoized selectors for efficient derived state
72+
- `Phoenix.SessionProcess.Redux.Subscription` - Subscription management for reactive state changes
73+
- `Phoenix.SessionProcess.Redux.LiveView` - LiveView integration helpers
74+
- `Phoenix.SessionProcess.MigrationExamples` - Migration examples for Redux
75+
- `Phoenix.SessionProcess.ReduxExamples` - Comprehensive Redux usage examples
76+
77+
**Configuration & Error Handling**:
78+
- `Phoenix.SessionProcess.Config` - Configuration management
79+
- `Phoenix.SessionProcess.Error` - Error types and messages
80+
81+
**Observability**:
82+
- `Phoenix.SessionProcess.Telemetry` - Telemetry event emission
83+
- `Phoenix.SessionProcess.TelemetryLogger` - Logging integration
84+
- `Phoenix.SessionProcess.Helpers` - General utilities
85+
4186
### Core Components
4287

4388
1. **Phoenix.SessionProcess** (lib/phoenix/session_process.ex:1)
4489
- Main module providing the public API
4590
- Delegates to ProcessSupervisor for actual process management
4691
- Provides two macros: `:process` (basic) and `:process_link` (with LiveView monitoring)
92+
- Key functions: `start/1-3`, `call/2-3`, `cast/2`, `terminate/1`, `started?/1`, `list_session/0`
4793

4894
2. **Phoenix.SessionProcess.Supervisor** (lib/phoenix/session_process/superviser.ex:1)
4995
- Top-level supervisor that manages the Registry, ProcessSupervisor, and Cleanup
5096
- Must be added to the application's supervision tree
97+
- Supervises: Registry, ProcessSupervisor, and Cleanup GenServer
5198

5299
3. **Phoenix.SessionProcess.ProcessSupervisor** (lib/phoenix/session_process/process_superviser.ex:1)
53100
- DynamicSupervisor that manages individual session processes
54101
- Handles starting, terminating, and communicating with session processes
55-
- Performs session validation and limit checks
102+
- Performs session validation and limit checks (max sessions, rate limiting)
103+
- Emits telemetry events for all operations
56104

57105
4. **Phoenix.SessionProcess.SessionId** (lib/phoenix/session_process/session_id.ex)
58106
- Plug that generates unique session IDs
59-
- Must be placed after `:fetch_session` plug
107+
- Must be placed after `:fetch_session` plug in router pipeline
108+
- Assigns session_id to conn.assigns for use in controllers/LiveViews
60109

61110
5. **Phoenix.SessionProcess.Cleanup** (lib/phoenix/session_process/cleanup.ex:1)
62-
- Automatic TTL-based session cleanup
111+
- GenServer for automatic TTL-based session cleanup
63112
- Schedules session expiration on creation
113+
- Runs cleanup tasks periodically
64114

65115
6. **Phoenix.SessionProcess.Redux** (lib/phoenix/session_process/redux.ex:1)
66-
- Redux-style state management with actions and reducers
116+
- Optional Redux-style state management with actions, reducers, subscriptions, and selectors
67117
- Provides time-travel debugging, middleware support, and action history
68-
69-
7. **Phoenix.SessionProcess.State** (lib/phoenix/session_process/state.ex:1)
70-
- Agent-based state storage with Redux-style dispatch support
71-
- Used for simpler state management scenarios
118+
- **Redux.Selector**: Memoized selectors with reselect-style composition for efficient derived state
119+
- **Redux.Subscription**: Subscribe to state changes with optional selectors (only notifies when selected values change)
120+
- **Redux.LiveView**: Helper module for LiveView integration with automatic assign updates
121+
- **Phoenix.PubSub integration**: Broadcast state changes across nodes for distributed applications
122+
- **Comprehensive telemetry**: Monitor Redux operations (dispatch, subscribe, selector cache hits/misses, PubSub broadcasts)
123+
- Best for complex applications requiring reactive UIs, predictable state updates, audit trails, or distributed state
124+
- Note: Most applications don't need this - standard GenServer state is sufficient
72125

73126
### Process Management Flow
74127

@@ -118,11 +171,16 @@ Configuration options:
118171

119172
## State Management Options
120173

121-
The library provides three state management approaches:
174+
The library provides two state management approaches:
175+
176+
1. **Standard GenServer State** (Recommended) - Full control with standard GenServer callbacks
177+
- Use `handle_call`, `handle_cast`, and `handle_info` to manage state
178+
- Simple, idiomatic Elixir - this is what you should use for 95% of cases
122179

123-
1. **Basic GenServer** - Full control with standard GenServer callbacks
124-
2. **Phoenix.SessionProcess.State** - Agent-based with simple get/put and Redux dispatch
125-
3. **Phoenix.SessionProcess.Redux** - Full Redux pattern with actions, reducers, middleware, time-travel debugging
180+
2. **Phoenix.SessionProcess.Redux** (Optional, Advanced) - Redux pattern for complex state machines
181+
- Actions, reducers, middleware, time-travel debugging
182+
- Only use if you need audit trails or complex state machine logic
183+
- Adds complexity - most applications don't need this
126184

127185
## Telemetry and Error Handling
128186

0 commit comments

Comments
 (0)