Files
pgsql-jellyfin/docs/PHASE3_SESSION_ISOLATION_COMPLETE.md
T
wjones 77e30685bb Complete multi-instance support: Phases 3–6 & deployment
- Implements Phases 3–6: session isolation, cache coordination, primary election, and file system monitor coordination for Jellyfin with PostgreSQL.
- Adds new database entities (Instance, DistributedLock, FileSystemChange) and EF model configurations.
- Includes SQL migration scripts and EF migration for all required tables, columns, and helper functions.
- Updates Device entity and JellyfinDbContext for multi-instance tracking.
- Integrates new DI services for instance registry, distributed locks, cache coordinator, and primary election.
- Adds publishing profiles (Win/Linux/FrameworkDependent) and automation script for deployment.
- Extensive documentation for architecture, setup, and publishing.
- All changes are backward compatible and build successfully.
2026-03-05 16:10:26 -05:00

173 lines
7.6 KiB
Markdown

# Phase 3 Implementation Summary: Session Isolation
## Overview
Phase 3 of multi-instance support ensures that user sessions are properly isolated between Jellyfin instances in a multi-instance deployment. Each instance now tracks which sessions belong to it and only manages its own sessions.
## Completed Tasks
### 1. ✅ Database Schema Updates
- **Added `InstanceId` column to `Device` entity** (`src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs`)
- Nullable `Guid?` for backward compatibility
- Tracks which instance last authenticated the device
- **Added `InstanceId` property to `SessionInfo` class** (`MediaBrowser.Controller/Session/SessionInfo.cs`)
- Non-nullable `Guid` property
- Set automatically when sessions are created
- Used for filtering sessions by instance
### 2. ✅ Instance Registry Service
- **Created `IInstanceRegistry` interface** (`Jellyfin.Server.Implementations/Clustering/IInstanceRegistry.cs`)
- Methods: RegisterInstanceAsync, UpdateHeartbeatAsync, ShutdownInstanceAsync
- GetActiveInstancesAsync, GetInstanceAsync, CleanupStaleInstancesAsync
- IsPrimaryInstanceAsync for primary election
- **Implemented `InstanceRegistry` service** (`Jellyfin.Server.Implementations/Clustering/InstanceRegistry.cs`)
- Generates unique InstanceId per instance (GUID)
- Automatic heartbeat mechanism (every 30 seconds)
- Registers instance on startup with hostname, ports, version
- Marks instance as shutdown on disposal
### 3. ✅ SessionManager Integration
- **Updated `SessionManager` constructor** (`Emby.Server.Implementations/Session/SessionManager.cs`)
- Added `IInstanceRegistry` parameter (optional for backward compatibility)
- Stores reference to instance registry
- **Modified session creation** (`CreateSessionInfo` method)
- Sets `InstanceId` on new `SessionInfo` objects
- Uses `_instanceRegistry.CurrentInstanceId` if available
- Falls back to `Guid.Empty` for single-instance deployments
- **Updated `Sessions` property**
- In multi-instance mode: filters sessions by CurrentInstanceId
- In single-instance mode: returns all sessions (backward compatible)
- Ensures each instance only sees its own sessions
### 4. ✅ Dependency Injection Registration
- **Registered services in `ApplicationHost`** (`Emby.Server.Implementations/ApplicationHost.cs`)
- Added `IInstanceRegistry``InstanceRegistry` (singleton)
- Added `IDistributedLockManager``DistributedLockManager` (singleton)
- Registered before SessionManager to ensure availability
### 5. ✅ Startup Integration
- **Modified `RunStartupTasksAsync`** (`Emby.Server.Implementations/ApplicationHost.cs`)
- Changed from synchronous to async (`Task` instead of `Task.CompletedTask`)
- Calls `RegisterInstanceAsync` after core initialization
- **Created `RegisterInstanceAsync` method**
- Retrieves network configuration for ports
- Registers instance in database with hostname, process ID, ports, version
- Logs successful registration with InstanceId
- Handles registration failures gracefully
### 6. ✅ Database Migration Updates
- **Updated EF Core migration** (`20260305000000_AddMultiInstanceSupport.cs`)
- Added `InstanceId` column to `Devices` table
- Created index on `Devices.InstanceId`
- Updated Down migration to drop column
- **Updated SQL migration script** (`sql/add_multi_instance_support.sql`)
- Added `ALTER TABLE Devices ADD COLUMN InstanceId UUID`
- Created `idx_devices_instance` index
- Added verification query for Devices table
## Architecture Benefits
### Session Isolation
- **Resource Separation**: Each instance manages only its own transcoding processes, network connections, and WebSocket sessions
- **No Interference**: One instance cannot accidentally terminate or modify another instance's active sessions
- **Clean Shutdown**: When an instance shuts down, only its sessions are affected
### Backward Compatibility
- **Optional Registry**: `IInstanceRegistry` parameter is optional, allowing single-instance deployments to continue working
- **Nullable Device.InstanceId**: Existing devices without InstanceId can still function
- **Fallback Logic**: SessionManager gracefully handles missing instance registry
### Scalability
- **Independent Scaling**: Add more instances without session conflicts
- **Load Balancer Support**: Users can connect to any instance, but their session is managed by one instance
- **Sticky Sessions**: Future enhancement - route users to the instance managing their session
## Usage
### Single Instance (Backward Compatible)
No configuration changes needed. The instance registry will register the instance, but session filtering is transparent.
### Multi-Instance Deployment
1. Apply database migration:
```bash
psql -U jellyfin -d jellyfin -f sql/add_multi_instance_support.sql
```
2. Start multiple Jellyfin instances:
- Each gets a unique InstanceId automatically
- Each registers itself in the database
- Each only manages its own sessions
3. Monitor instances:
```sql
SELECT * FROM library."Instances" WHERE "Status" = 'Active';
```
4. View sessions by instance:
```sql
SELECT s."Id", s."DeviceName", i."Hostname", i."HttpPort"
FROM library."Devices" s
LEFT JOIN library."Instances" i ON s."InstanceId" = i."InstanceId"
WHERE i."Status" = 'Active';
```
## Testing Checklist
- [ ] Start single instance - verify it registers
- [ ] Create a session - verify InstanceId is set
- [ ] View sessions API - verify sessions are returned
- [ ] Shutdown instance - verify status updated to 'Shutdown'
- [ ] Start two instances - verify both register with different InstanceIds
- [ ] Create session on Instance A - verify Instance B doesn't see it
- [ ] Create session on Instance B - verify Instance A doesn't see it
- [ ] Stop Instance A - verify Instance B continues working
- [ ] Check heartbeat mechanism - verify LastHeartbeat updates every 30s
- [ ] Test stale instance detection - stop instance without graceful shutdown, verify marked as 'Failed' after 2 minutes
## Next Steps
**Phase 4: Cache Coordination**
- Implement PostgreSQL LISTEN/NOTIFY for cache invalidation
- Create CacheCoordinator service
- Hook into item update events
- Enable multi-instance cache consistency
**Phase 5: Primary Instance Election**
- Implement primary election algorithm
- Coordinate scheduled tasks to run only on primary
- Coordinate database migrations
- Handle primary failover
**Phase 6: File System Monitor Coordination**
- Create FileSystemChanges table
- Update LibraryMonitor to write to database
- Reduce duplicate file scanning across instances
## Files Modified
### New Files Created
- `Jellyfin.Server.Implementations/Clustering/IInstanceRegistry.cs`
- `Jellyfin.Server.Implementations/Clustering/InstanceRegistry.cs`
### Files Modified
- `src/Jellyfin.Database/Jellyfin.Database.Implementations/Entities/Security/Device.cs` - Added InstanceId property
- `MediaBrowser.Controller/Session/SessionInfo.cs` - Added InstanceId property
- `Emby.Server.Implementations/Session/SessionManager.cs` - Integrated InstanceRegistry, session filtering
- `Emby.Server.Implementations/ApplicationHost.cs` - Service registration, instance registration on startup
- `src/Jellyfin.Database/Jellyfin.Database.Providers.Postgres/Migrations/20260305000000_AddMultiInstanceSupport.cs` - Added Devices.InstanceId
- `sql/add_multi_instance_support.sql` - Added Devices.InstanceId
## Build Status
✅ Build successful (only IDE warnings, no compilation errors)
## Compatibility
- ✅ Backward compatible with single-instance deployments
- ✅ No breaking changes to existing APIs
- ✅ Nullable columns for incremental adoption
- ✅ Optional DI parameters for gradual integration