# 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