Fix concurrent ffmpeg segment racing
This is a nasty one. The failure mode is: 1. Request A started FFmpeg and waited for a segment. 2. Request B requested an earlier or far away segment. 3. Jellyfin thought FFmpeg should to restart at a different position. 4. Request B killed the existing transcoding job. 5. Killing that job cancelled the same token request A was using. 6. The cancellation produced http 500 to request A. To fix this: we lock transcoding job state changes and segment handling per playlist, and use a thread safe counter to track how many http responses are still using each job’s segments. A job is only stopped or replaced once that counter reaches zero.
This commit is contained in:
@@ -15,6 +15,7 @@ public sealed class TranscodingJob : IDisposable
|
||||
private readonly Lock _processLock = new();
|
||||
private readonly Lock _timerLock = new();
|
||||
|
||||
private int _activeRequestCount;
|
||||
private Timer? _killTimer;
|
||||
|
||||
/// <summary>
|
||||
@@ -64,7 +65,11 @@ public sealed class TranscodingJob : IDisposable
|
||||
/// <summary>
|
||||
/// Gets or sets the active request count.
|
||||
/// </summary>
|
||||
public int ActiveRequestCount { get; set; }
|
||||
public int ActiveRequestCount
|
||||
{
|
||||
get => Volatile.Read(ref _activeRequestCount);
|
||||
set => Volatile.Write(ref _activeRequestCount, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets device id.
|
||||
@@ -151,6 +156,20 @@ public sealed class TranscodingJob : IDisposable
|
||||
/// </summary>
|
||||
public int PingTimeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Increments the active request count.
|
||||
/// </summary>
|
||||
/// <returns>The incremented count.</returns>
|
||||
public int IncrementActiveRequestCount()
|
||||
=> Interlocked.Increment(ref _activeRequestCount);
|
||||
|
||||
/// <summary>
|
||||
/// Decrements the active request count.
|
||||
/// </summary>
|
||||
/// <returns>The decremented count.</returns>
|
||||
public int DecrementActiveRequestCount()
|
||||
=> Interlocked.Decrement(ref _activeRequestCount);
|
||||
|
||||
/// <summary>
|
||||
/// Stop kill timer.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user