Postgres perf, path migration, and shutdown race fixes
- Major query performance boost: replaced correlated subqueries with DistinctBy() in BaseItemRepository, added episode deduplication index, and increased default command timeout to 120s. - Fixed LibraryMonitor shutdown race: added disposal checks and exception handling in FileRefresher to prevent ObjectDisposedException. - Added PowerShell and SQL utilities for fixing Linux paths in config files and database; new scripts for WebDir and path migration. - Auto-fix for WebDir in startup.json on load; new helper scripts and docs. - Added automated weekly DB performance monitoring scripts and reporting. - Expanded documentation and README for all fixes, scripts, and migration steps. - Updated SQL scripts for index creation and diagnostics; improved output handling. - Updated db-config defaults and added new diagnostic/report files.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# LibraryMonitor Disposal Fix - Summary
|
||||
|
||||
## What Was Fixed
|
||||
|
||||
Fixed `ObjectDisposedException` that occurred during application shutdown when file system monitor timer callbacks executed after the service provider was disposed.
|
||||
|
||||
## Error Message
|
||||
|
||||
```
|
||||
System.ObjectDisposedException: Cannot access a disposed object.
|
||||
Object name: 'IServiceProvider'.
|
||||
at Emby.Server.Implementations.IO.LibraryMonitor: Error processing directory changes
|
||||
```
|
||||
|
||||
## Root Cause
|
||||
|
||||
Race condition during shutdown:
|
||||
1. Application begins shutdown and disposes `IServiceProvider`
|
||||
2. `LibraryMonitor` disposal starts
|
||||
3. `FileRefresher` timer callback fires **before** timer is fully disposed
|
||||
4. Callback tries to access database through disposed service provider
|
||||
5. Exception thrown
|
||||
|
||||
## Solution
|
||||
|
||||
Added three layers of protection in `FileRefresher.cs`:
|
||||
|
||||
### 1. Early Exit Check
|
||||
```csharp
|
||||
private void OnTimerCallback(object? state)
|
||||
{
|
||||
if (_disposed) return; // ← Added
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Post-Timer-Disposal Check
|
||||
```csharp
|
||||
DisposeTimer();
|
||||
if (_disposed) return; // ← Added
|
||||
ProcessPathChanges(paths);
|
||||
```
|
||||
|
||||
### 3. Exception Handling
|
||||
```csharp
|
||||
try
|
||||
{
|
||||
itemsToRefresh = paths.Select(GetAffectedBaseItem)...;
|
||||
}
|
||||
catch (ObjectDisposedException) // ← Added
|
||||
{
|
||||
_logger.LogDebug("Service provider disposed during shutdown");
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
## Impact
|
||||
|
||||
- ✅ Clean application shutdowns
|
||||
- ✅ No more `ObjectDisposedException` errors in logs
|
||||
- ✅ No impact on normal operation
|
||||
- ✅ Graceful handling of shutdown race conditions
|
||||
|
||||
## Files Modified
|
||||
|
||||
- **Emby.Server.Implementations\IO\FileRefresher.cs**
|
||||
- Added disposal checks in `OnTimerCallback`
|
||||
- Added disposal handling in `ProcessPathChanges`
|
||||
|
||||
## Testing
|
||||
|
||||
- ✅ Build successful
|
||||
- ✅ No breaking changes
|
||||
- ✅ Addresses shutdown race condition
|
||||
|
||||
## Documentation
|
||||
|
||||
- **Full Guide:** [LIBRARYMONITOR_DISPOSAL_FIX.md](./LIBRARYMONITOR_DISPOSAL_FIX.md)
|
||||
- **README Updated:** Added to "Error Fixes & Troubleshooting" section
|
||||
|
||||
## Related Issues
|
||||
|
||||
This error typically appears when:
|
||||
- Application is shutting down
|
||||
- File system changes occur during shutdown
|
||||
- Timer callbacks execute after service disposal begins
|
||||
|
||||
The fix ensures these scenarios are handled gracefully.
|
||||
|
||||
---
|
||||
|
||||
**Status:** ✅ Complete
|
||||
**Risk Level:** Low (shutdown-only scenario)
|
||||
**User Impact:** Reduced error noise in logs during shutdown
|
||||
Reference in New Issue
Block a user