aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-09-05 09:58:04 +0200
committerShadowghost <Ghost_of_Stone@web.de>2026-09-05 09:59:12 +0200
commitf8470630be0f3fa7b8052ebd822f23531d30da2f (patch)
treedc7cf005acfdb2d9ee22a21f886176d3ada25cf5
parente5cd3381acefbe13aa36a26059c28629e23e1944 (diff)
Retire runners that are cancelled before they start
-rw-r--r--MediaBrowser.Controller/LibraryTaskScheduler/LimitedConcurrencyLibraryScheduler.cs4
-rw-r--r--tests/Jellyfin.Controller.Tests/LibraryTaskScheduler/LimitedConcurrencyLibrarySchedulerTests.cs6
2 files changed, 6 insertions, 4 deletions
diff --git a/MediaBrowser.Controller/LibraryTaskScheduler/LimitedConcurrencyLibraryScheduler.cs b/MediaBrowser.Controller/LibraryTaskScheduler/LimitedConcurrencyLibraryScheduler.cs
index 3c6ffe3cbd..be75117b6f 100644
--- a/MediaBrowser.Controller/LibraryTaskScheduler/LimitedConcurrencyLibraryScheduler.cs
+++ b/MediaBrowser.Controller/LibraryTaskScheduler/LimitedConcurrencyLibraryScheduler.cs
@@ -191,12 +191,14 @@ public sealed class LimitedConcurrencyLibraryScheduler : ILimitedConcurrencyLibr
// Keyed on its own stop source, because cancelling that is what reaches the linked
// source the runner waits on. Cancellation does not travel the other way.
+ // Started without the runner's own token: a task cancelled before it is scheduled
+ // never runs its body, so it would never take itself out of _taskRunners again.
_taskRunners.Add(
stopToken,
Task.Factory.StartNew(
ItemWorker,
(stopToken, combinedSource),
- combinedSource.Token,
+ CancellationToken.None,
TaskCreationOptions.PreferFairness,
TaskScheduler.Default));
}
diff --git a/tests/Jellyfin.Controller.Tests/LibraryTaskScheduler/LimitedConcurrencyLibrarySchedulerTests.cs b/tests/Jellyfin.Controller.Tests/LibraryTaskScheduler/LimitedConcurrencyLibrarySchedulerTests.cs
index f776e893a0..686d839f4f 100644
--- a/tests/Jellyfin.Controller.Tests/LibraryTaskScheduler/LimitedConcurrencyLibrarySchedulerTests.cs
+++ b/tests/Jellyfin.Controller.Tests/LibraryTaskScheduler/LimitedConcurrencyLibrarySchedulerTests.cs
@@ -65,7 +65,7 @@ namespace Jellyfin.Controller.Tests.LibraryTaskScheduler
/// so a shutdown has to reach them. It does not travel from the linked source back to the one
/// the cleanup cancels, which is what made them immortal.
/// </summary>
- /// <returns><placeholder>A <see cref="Task"/> representing the asynchronous unit test.</placeholder></returns>
+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task ApplicationStopping_RetiresRunners()
{
@@ -88,7 +88,7 @@ namespace Jellyfin.Controller.Tests.LibraryTaskScheduler
/// The cleanup used to be a one shot: it never released the scheduling slot it took, so
/// every runner spawned after the first pass stayed around for the lifetime of the server.
/// </summary>
- /// <returns><placeholder>A <see cref="Task"/> representing the asynchronous unit test.</placeholder></returns>
+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task Enqueue_RetiresIdleRunnersAfterEveryOperation()
{
@@ -110,7 +110,7 @@ namespace Jellyfin.Controller.Tests.LibraryTaskScheduler
/// Disposing used to sit out the rest of the cleanup grace period, holding up shutdown for
/// up to a minute.
/// </summary>
- /// <returns><placeholder>A <see cref="Task"/> representing the asynchronous unit test.</placeholder></returns>
+ /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task DisposeAsync_DoesNotWaitOutTheGracePeriod()
{