< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.ScheduledTasks.TaskManager
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
Line coverage
60%
Covered lines: 47
Uncovered lines: 31
Coverable lines: 78
Total lines: 263
Line coverage: 60.2%
Branch coverage
47%
Covered branches: 17
Total branches: 36
Branch coverage: 47.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 7/22/2025 - 12:11:20 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2637/26/2025 - 12:11:20 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/1/2025 - 12:11:32 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/2/2025 - 12:11:30 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/3/2025 - 12:10:08 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2638/8/2025 - 12:11:52 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/9/2025 - 12:11:47 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2638/11/2025 - 12:11:38 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/14/2025 - 12:11:05 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/15/2025 - 12:10:51 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/16/2025 - 12:10:44 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2638/17/2025 - 12:10:48 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/18/2025 - 12:09:37 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2638/20/2025 - 12:10:54 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/21/2025 - 12:09:39 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/22/2025 - 12:09:44 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/24/2025 - 12:11:19 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2638/25/2025 - 12:11:25 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/29/2025 - 12:09:55 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2638/30/2025 - 12:09:58 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/2/2025 - 12:10:53 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/3/2025 - 12:11:08 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/10/2025 - 12:11:36 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/11/2025 - 12:10:04 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/15/2025 - 12:10:55 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/17/2025 - 12:11:23 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/18/2025 - 12:09:59 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/19/2025 - 12:11:12 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/21/2025 - 12:11:25 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/24/2025 - 12:10:54 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/25/2025 - 12:11:18 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 26310/3/2025 - 12:11:15 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 26310/4/2025 - 12:10:06 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 26310/6/2025 - 12:11:10 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 26310/7/2025 - 12:11:28 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 26310/26/2025 - 12:11:38 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 26310/27/2025 - 12:11:33 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 263 7/22/2025 - 12:11:20 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2637/26/2025 - 12:11:20 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/1/2025 - 12:11:32 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/2/2025 - 12:11:30 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/3/2025 - 12:10:08 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2638/8/2025 - 12:11:52 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/9/2025 - 12:11:47 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2638/11/2025 - 12:11:38 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/14/2025 - 12:11:05 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/15/2025 - 12:10:51 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/16/2025 - 12:10:44 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2638/17/2025 - 12:10:48 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/18/2025 - 12:09:37 AM Line coverage: 70.5% (55/78) Branch coverage: 58.3% (21/36) Total lines: 2638/20/2025 - 12:10:54 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/21/2025 - 12:09:39 AM Line coverage: 60.2% (47/78) Branch coverage: 44.4% (16/36) Total lines: 2638/22/2025 - 12:09:44 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/24/2025 - 12:11:19 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2638/25/2025 - 12:11:25 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2638/29/2025 - 12:09:55 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2638/30/2025 - 12:09:58 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/2/2025 - 12:10:53 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/3/2025 - 12:11:08 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/10/2025 - 12:11:36 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/11/2025 - 12:10:04 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/15/2025 - 12:10:55 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/17/2025 - 12:11:23 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/18/2025 - 12:09:59 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/19/2025 - 12:11:12 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/21/2025 - 12:11:25 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 2639/24/2025 - 12:10:54 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 2639/25/2025 - 12:11:18 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 26310/3/2025 - 12:11:15 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 26310/4/2025 - 12:10:06 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 26310/6/2025 - 12:11:10 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 26310/7/2025 - 12:11:28 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 26310/26/2025 - 12:11:38 AM Line coverage: 70.5% (55/78) Branch coverage: 61.1% (22/36) Total lines: 26310/27/2025 - 12:11:33 AM Line coverage: 60.2% (47/78) Branch coverage: 47.2% (17/36) Total lines: 263

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
CancelIfRunningAndQueue(...)100%22100%
CancelIfRunningAndQueue()100%11100%
CancelIfRunning()0%620%
QueueScheduledTask(...)75%4480%
QueueScheduledTask()100%210%
QueueIfNotRunning()0%2040%
Execute()0%4260%
QueueScheduledTask(...)50%2280%
QueueScheduledTask(...)50%2277.77%
AddTasks(...)100%11100%
Dispose()100%11100%
Dispose(...)100%22100%
Cancel(...)100%210%
Execute(...)100%11100%
OnTaskExecuting(...)100%22100%
OnTaskCompleted(...)100%22100%
ExecuteQueuedTasks()50%18845.45%

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs

#LineLine coverage
 1using System;
 2using System.Collections.Concurrent;
 3using System.Collections.Generic;
 4using System.Linq;
 5using System.Threading.Tasks;
 6using Jellyfin.Data.Events;
 7using MediaBrowser.Common.Configuration;
 8using MediaBrowser.Model.Tasks;
 9using Microsoft.Extensions.Logging;
 10
 11namespace Emby.Server.Implementations.ScheduledTasks;
 12
 13/// <summary>
 14/// Class TaskManager.
 15/// </summary>
 16public class TaskManager : ITaskManager
 17{
 18    /// <summary>
 19    /// The _task queue.
 20    /// </summary>
 2121    private readonly ConcurrentQueue<Tuple<Type, TaskOptions>> _taskQueue =
 2122        new ConcurrentQueue<Tuple<Type, TaskOptions>>();
 23
 24    private readonly IApplicationPaths _applicationPaths;
 25    private readonly ILogger<TaskManager> _logger;
 26
 27    /// <summary>
 28    /// Initializes a new instance of the <see cref="TaskManager" /> class.
 29    /// </summary>
 30    /// <param name="applicationPaths">The application paths.</param>
 31    /// <param name="logger">The logger.</param>
 32    public TaskManager(
 33        IApplicationPaths applicationPaths,
 34        ILogger<TaskManager> logger)
 35    {
 2136        _applicationPaths = applicationPaths;
 2137        _logger = logger;
 38
 2139        ScheduledTasks = [];
 2140    }
 41
 42    /// <inheritdoc />
 43    public event EventHandler<GenericEventArgs<IScheduledTaskWorker>>? TaskExecuting;
 44
 45    /// <inheritdoc />
 46    public event EventHandler<TaskCompletionEventArgs>? TaskCompleted;
 47
 48    /// <inheritdoc />
 49    public IReadOnlyList<IScheduledTaskWorker> ScheduledTasks { get; private set; }
 50
 51    /// <inheritdoc />
 52    public void CancelIfRunningAndQueue<T>(TaskOptions options)
 53        where T : IScheduledTask
 54    {
 2055        var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
 2056        ((ScheduledTaskWorker)task).CancelIfRunning();
 57
 2058        QueueScheduledTask<T>(options);
 2059    }
 60
 61    /// <inheritdoc />
 62    public void CancelIfRunningAndQueue<T>()
 63            where T : IScheduledTask
 64    {
 2065        CancelIfRunningAndQueue<T>(new TaskOptions());
 2066    }
 67
 68    /// <inheritdoc />
 69    public void CancelIfRunning<T>()
 70                where T : IScheduledTask
 71    {
 072        var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
 073        ((ScheduledTaskWorker)task).CancelIfRunning();
 074    }
 75
 76    /// <inheritdoc />
 77    public void QueueScheduledTask<T>(TaskOptions options)
 78        where T : IScheduledTask
 79    {
 2080        var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T));
 81
 2082        if (scheduledTask is null)
 83        {
 084            _logger.LogError("Unable to find scheduled task of type {Type} in QueueScheduledTask.", typeof(T).Name);
 85        }
 86        else
 87        {
 2088            QueueScheduledTask(scheduledTask, options);
 89        }
 2090    }
 91
 92    /// <inheritdoc />
 93    public void QueueScheduledTask<T>()
 94        where T : IScheduledTask
 95    {
 096        QueueScheduledTask<T>(new TaskOptions());
 097    }
 98
 99    /// <inheritdoc />
 100    public void QueueIfNotRunning<T>()
 101        where T : IScheduledTask
 102    {
 0103        var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
 104
 0105        if (task.State != TaskState.Running)
 106        {
 0107            QueueScheduledTask<T>(new TaskOptions());
 108        }
 0109    }
 110
 111    /// <inheritdoc />
 112    public void Execute<T>()
 113        where T : IScheduledTask
 114    {
 0115        var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == typeof(T));
 116
 0117        if (scheduledTask is null)
 118        {
 0119            _logger.LogError("Unable to find scheduled task of type {Type} in Execute.", typeof(T).Name);
 120        }
 121        else
 122        {
 0123            var type = scheduledTask.ScheduledTask.GetType();
 124
 0125            _logger.LogDebug("Queuing task {Name}", type.Name);
 126
 0127            lock (_taskQueue)
 128            {
 0129                if (scheduledTask.State == TaskState.Idle)
 130                {
 0131                    Execute(scheduledTask, new TaskOptions());
 132                }
 0133            }
 134        }
 0135    }
 136
 137    /// <inheritdoc />
 138    public void QueueScheduledTask(IScheduledTask task, TaskOptions options)
 139    {
 6140        var scheduledTask = ScheduledTasks.FirstOrDefault(t => t.ScheduledTask.GetType() == task.GetType());
 141
 6142        if (scheduledTask is null)
 143        {
 0144            _logger.LogError("Unable to find scheduled task of type {Type} in QueueScheduledTask.", task.GetType().Name)
 145        }
 146        else
 147        {
 6148            QueueScheduledTask(scheduledTask, options);
 149        }
 6150    }
 151
 152    /// <summary>
 153    /// Queues the scheduled task.
 154    /// </summary>
 155    /// <param name="task">The task.</param>
 156    /// <param name="options">The task options.</param>
 157    private void QueueScheduledTask(IScheduledTaskWorker task, TaskOptions options)
 158    {
 26159        var type = task.ScheduledTask.GetType();
 160
 26161        _logger.LogDebug("Queuing task {Name}", type.Name);
 162
 26163        lock (_taskQueue)
 164        {
 26165            if (task.State == TaskState.Idle)
 166            {
 26167                Execute(task, options);
 26168                return;
 169            }
 170
 0171            _taskQueue.Enqueue(new Tuple<Type, TaskOptions>(type, options));
 0172        }
 26173    }
 174
 175    /// <inheritdoc />
 176    public void AddTasks(IEnumerable<IScheduledTask> tasks)
 177    {
 21178        var list = tasks.Select(t => new ScheduledTaskWorker(t, _applicationPaths, this, _logger));
 179
 21180        ScheduledTasks = ScheduledTasks.Concat(list).ToArray();
 21181    }
 182
 183    /// <inheritdoc />
 184    public void Dispose()
 185    {
 21186        Dispose(true);
 21187        GC.SuppressFinalize(this);
 21188    }
 189
 190    /// <summary>
 191    /// Releases unmanaged and - optionally - managed resources.
 192    /// </summary>
 193    /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only 
 194    protected virtual void Dispose(bool dispose)
 195    {
 882196        foreach (var task in ScheduledTasks)
 197        {
 420198            task.Dispose();
 199        }
 21200    }
 201
 202    /// <inheritdoc />
 203    public void Cancel(IScheduledTaskWorker task)
 204    {
 0205        ((ScheduledTaskWorker)task).Cancel();
 0206    }
 207
 208    /// <inheritdoc />
 209    public Task Execute(IScheduledTaskWorker task, TaskOptions options)
 210    {
 26211        return ((ScheduledTaskWorker)task).Execute(options);
 212    }
 213
 214    /// <summary>
 215    /// Called when [task executing].
 216    /// </summary>
 217    /// <param name="task">The task.</param>
 218    internal void OnTaskExecuting(IScheduledTaskWorker task)
 219    {
 26220        TaskExecuting?.Invoke(this, new GenericEventArgs<IScheduledTaskWorker>(task));
 23221    }
 222
 223    /// <summary>
 224    /// Called when [task completed].
 225    /// </summary>
 226    /// <param name="task">The task.</param>
 227    /// <param name="result">The result.</param>
 228    internal void OnTaskCompleted(IScheduledTaskWorker task, TaskResult result)
 229    {
 31230        TaskCompleted?.Invoke(task, new TaskCompletionEventArgs(task, result));
 231
 31232        ExecuteQueuedTasks();
 31233    }
 234
 235    /// <summary>
 236    /// Executes the queued tasks.
 237    /// </summary>
 238    private void ExecuteQueuedTasks()
 239    {
 31240        lock (_taskQueue)
 241        {
 31242            var list = new List<Tuple<Type, TaskOptions>>();
 243
 31244            while (_taskQueue.TryDequeue(out var item))
 245            {
 0246                if (list.All(i => i.Item1 != item.Item1))
 247                {
 0248                    list.Add(item);
 249                }
 0250            }
 251
 62252            foreach (var enqueuedType in list)
 253            {
 0254                var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == enqueuedType.Item1);
 255
 0256                if (scheduledTask.State == TaskState.Idle)
 257                {
 0258                    Execute(scheduledTask, enqueuedType.Item2);
 259                }
 260            }
 261        }
 31262    }
 263}