2022-04-14 19:42:15 +00:00
|
|
|
// (c) Copyright Ascensio System SIA 2010-2022
|
|
|
|
//
|
|
|
|
// This program is a free software product.
|
|
|
|
// You can redistribute it and/or modify it under the terms
|
|
|
|
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
|
|
|
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
|
|
|
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
|
|
|
// any third-party rights.
|
|
|
|
//
|
|
|
|
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
|
|
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
|
|
|
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
|
|
//
|
|
|
|
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
|
|
|
//
|
|
|
|
// The interactive user interfaces in modified source and object code versions of the Program must
|
|
|
|
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
|
|
|
//
|
|
|
|
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
|
|
|
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
|
|
|
// trademark law for use of our trademarks.
|
|
|
|
//
|
|
|
|
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
|
|
|
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
|
|
|
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
|
|
|
2019-05-15 14:56:09 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* (c) Copyright Ascensio System Limited 2010-2018
|
|
|
|
*
|
|
|
|
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
|
|
|
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
|
|
|
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
|
|
|
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
|
|
|
*
|
|
|
|
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
|
|
|
*
|
|
|
|
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
|
|
|
*
|
|
|
|
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
|
|
|
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
|
|
|
*
|
|
|
|
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
|
|
|
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
|
|
|
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
|
|
|
* in every copy of the program you distribute.
|
|
|
|
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
|
|
|
*
|
|
|
|
*/
|
2022-04-14 12:21:06 +00:00
|
|
|
|
2022-03-25 16:15:28 +00:00
|
|
|
using Microsoft.Extensions.Caching.Distributed;
|
2022-03-15 18:00:53 +00:00
|
|
|
|
2022-02-03 15:26:44 +00:00
|
|
|
namespace ASC.Common.Threading;
|
|
|
|
|
2022-03-22 12:10:05 +00:00
|
|
|
[Transient]
|
|
|
|
public class DistributedTaskQueue
|
2019-10-14 08:23:45 +00:00
|
|
|
{
|
2022-04-01 13:54:21 +00:00
|
|
|
public const string QUEUE_DEFAULT_PREFIX = "asc_distributed_task_queue_";
|
|
|
|
public static readonly int INSTANCE_ID = Process.GetCurrentProcess().Id;
|
2022-03-26 13:31:13 +00:00
|
|
|
|
2022-03-22 12:10:05 +00:00
|
|
|
private readonly ConcurrentDictionary<string, CancellationTokenSource> _cancelations;
|
|
|
|
private readonly IServiceProvider _serviceProvider;
|
|
|
|
private readonly ICacheNotify<DistributedTaskCancelation> _cancellationCacheNotify;
|
2022-03-25 16:15:28 +00:00
|
|
|
private readonly IDistributedCache _distributedCache;
|
2022-03-25 18:00:43 +00:00
|
|
|
private readonly ILog _logger;
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-03-29 13:52:08 +00:00
|
|
|
/// <summary>
|
|
|
|
/// setup -1 for infinity thread counts
|
|
|
|
/// </summary>
|
2022-04-01 13:54:21 +00:00
|
|
|
private int _maxThreadsCount = 1;
|
2022-03-22 12:10:05 +00:00
|
|
|
private string _name;
|
2022-04-01 13:54:21 +00:00
|
|
|
private readonly int _timeUntilUnregisterInSeconds = 60;
|
2022-03-22 12:10:05 +00:00
|
|
|
private TaskScheduler Scheduler { get; set; } = TaskScheduler.Default;
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-03-22 12:10:05 +00:00
|
|
|
public DistributedTaskQueue(IServiceProvider serviceProvider,
|
2022-02-14 09:05:05 +00:00
|
|
|
ICacheNotify<DistributedTaskCancelation> cancelTaskNotify,
|
2022-03-25 18:00:43 +00:00
|
|
|
IDistributedCache distributedCache,
|
|
|
|
IOptionsMonitor<ILog> options)
|
2022-02-01 14:51:29 +00:00
|
|
|
|
2022-03-22 12:10:05 +00:00
|
|
|
{
|
2022-03-25 16:15:28 +00:00
|
|
|
_distributedCache = distributedCache;
|
2022-03-22 12:10:05 +00:00
|
|
|
_serviceProvider = serviceProvider;
|
|
|
|
_cancellationCacheNotify = cancelTaskNotify;
|
|
|
|
_cancelations = new ConcurrentDictionary<string, CancellationTokenSource>();
|
2022-03-25 18:00:43 +00:00
|
|
|
_logger = options.CurrentValue;
|
2019-10-14 08:23:45 +00:00
|
|
|
|
2022-03-22 12:10:05 +00:00
|
|
|
_cancellationCacheNotify.Subscribe((c) =>
|
2019-10-14 08:23:45 +00:00
|
|
|
{
|
2022-03-22 12:10:05 +00:00
|
|
|
if (_cancelations.TryGetValue(c.Id, out var s))
|
2022-02-08 11:07:28 +00:00
|
|
|
{
|
|
|
|
s.Cancel();
|
|
|
|
}
|
2022-02-14 09:05:05 +00:00
|
|
|
}, CacheNotifyAction.Remove);
|
2022-02-23 19:42:34 +00:00
|
|
|
}
|
2022-02-03 15:26:44 +00:00
|
|
|
|
|
|
|
public string Name
|
|
|
|
{
|
2022-02-11 13:17:55 +00:00
|
|
|
get => _name;
|
2022-03-26 13:31:13 +00:00
|
|
|
set => _name = QUEUE_DEFAULT_PREFIX + value;
|
2019-10-14 08:23:45 +00:00
|
|
|
}
|
2020-07-13 15:26:21 +00:00
|
|
|
|
2022-02-11 13:17:55 +00:00
|
|
|
public int MaxThreadsCount
|
2022-02-03 15:26:44 +00:00
|
|
|
{
|
2022-03-02 15:25:28 +00:00
|
|
|
get
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-03-02 15:25:28 +00:00
|
|
|
return _maxThreadsCount;
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2021-05-13 08:23:44 +00:00
|
|
|
|
2022-03-02 15:25:28 +00:00
|
|
|
set
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-04-14 12:21:06 +00:00
|
|
|
Scheduler = value <= 0
|
2022-02-11 13:17:55 +00:00
|
|
|
? TaskScheduler.Default
|
|
|
|
: new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, value).ConcurrentScheduler;
|
2022-02-04 09:56:15 +00:00
|
|
|
|
2022-03-02 15:25:28 +00:00
|
|
|
if (value > 0)
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-03-02 15:25:28 +00:00
|
|
|
_maxThreadsCount = value;
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2022-02-08 11:07:28 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-03-25 18:00:43 +00:00
|
|
|
public void EnqueueTask(DistributedTaskProgress taskProgress)
|
2022-02-08 11:07:28 +00:00
|
|
|
{
|
2022-03-25 18:00:43 +00:00
|
|
|
EnqueueTask((a, b) => taskProgress.RunJob(), taskProgress);
|
2022-02-08 11:07:28 +00:00
|
|
|
}
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-03-25 18:00:43 +00:00
|
|
|
public void EnqueueTask(Action<DistributedTask, CancellationToken> action, DistributedTask distributedTask = null)
|
2022-02-03 15:26:44 +00:00
|
|
|
{
|
2022-02-08 11:07:28 +00:00
|
|
|
if (distributedTask == null)
|
|
|
|
{
|
|
|
|
distributedTask = new DistributedTask();
|
|
|
|
}
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
distributedTask.InstanceId = INSTANCE_ID;
|
2022-02-03 15:26:44 +00:00
|
|
|
|
|
|
|
var cancelation = new CancellationTokenSource();
|
|
|
|
var token = cancelation.Token;
|
2022-03-22 12:10:05 +00:00
|
|
|
_cancelations[distributedTask.Id] = cancelation;
|
2022-02-03 15:26:44 +00:00
|
|
|
|
|
|
|
var task = new Task(() => { action(distributedTask, token); }, token, TaskCreationOptions.LongRunning);
|
|
|
|
|
|
|
|
task.ConfigureAwait(false)
|
|
|
|
.GetAwaiter()
|
|
|
|
.OnCompleted(() => OnCompleted(task, distributedTask.Id));
|
|
|
|
|
|
|
|
distributedTask.Status = DistributedTaskStatus.Running;
|
|
|
|
|
|
|
|
if (distributedTask.Publication == null)
|
2022-02-08 11:07:28 +00:00
|
|
|
{
|
2022-02-03 15:26:44 +00:00
|
|
|
distributedTask.Publication = GetPublication();
|
2022-02-08 11:07:28 +00:00
|
|
|
}
|
2020-07-13 15:26:21 +00:00
|
|
|
|
2022-02-03 15:26:44 +00:00
|
|
|
distributedTask.PublishChanges();
|
|
|
|
|
|
|
|
task.Start(Scheduler);
|
2022-03-25 18:00:43 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
_logger.TraceFormat("EnqueueTask '{DistributedTaskId}' by instanse id '{InstanceId}'", distributedTask.Id, INSTANCE_ID);
|
2022-03-25 18:00:43 +00:00
|
|
|
|
2022-02-03 15:26:44 +00:00
|
|
|
}
|
|
|
|
|
2022-03-25 18:00:43 +00:00
|
|
|
public void EnqueueTask(Func<DistributedTask, CancellationToken, Task> action, DistributedTask distributedTask = null)
|
2022-02-23 19:42:34 +00:00
|
|
|
{
|
|
|
|
if (distributedTask == null)
|
|
|
|
{
|
|
|
|
distributedTask = new DistributedTask();
|
2021-05-13 08:23:44 +00:00
|
|
|
}
|
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
distributedTask.InstanceId = INSTANCE_ID;
|
2021-05-13 08:23:44 +00:00
|
|
|
|
2022-02-23 19:42:34 +00:00
|
|
|
var cancelation = new CancellationTokenSource();
|
|
|
|
var token = cancelation.Token;
|
2022-03-22 12:10:05 +00:00
|
|
|
_cancelations[distributedTask.Id] = cancelation;
|
2020-08-06 18:07:27 +00:00
|
|
|
|
2022-04-14 19:42:15 +00:00
|
|
|
var task = new Task(() =>
|
|
|
|
{
|
|
|
|
var t = action(distributedTask, token);
|
|
|
|
t.ConfigureAwait(false)
|
|
|
|
.GetAwaiter()
|
|
|
|
.OnCompleted(() => OnCompleted(t, distributedTask.Id));
|
|
|
|
}, token, TaskCreationOptions.LongRunning);
|
2020-07-13 15:26:21 +00:00
|
|
|
|
2022-04-14 19:42:15 +00:00
|
|
|
task.ConfigureAwait(false);
|
2022-02-23 10:42:14 +00:00
|
|
|
|
2022-02-23 19:42:34 +00:00
|
|
|
distributedTask.Status = DistributedTaskStatus.Running;
|
2020-07-13 15:26:21 +00:00
|
|
|
|
2022-02-23 19:42:34 +00:00
|
|
|
if (distributedTask.Publication == null)
|
2020-07-13 15:26:21 +00:00
|
|
|
{
|
2022-02-23 19:42:34 +00:00
|
|
|
distributedTask.Publication = GetPublication();
|
2020-07-13 15:26:21 +00:00
|
|
|
}
|
2022-02-23 19:42:34 +00:00
|
|
|
distributedTask.PublishChanges();
|
|
|
|
|
|
|
|
task.Start(Scheduler);
|
2020-07-13 15:26:21 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
_logger.TraceFormat("EnqueueTask '{DistributedTaskId}' by instanse id '{InstanceId}'", distributedTask.Id, INSTANCE_ID);
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
public IEnumerable<DistributedTask> GetAllTasks(int? instanceId = null)
|
2022-02-01 14:51:29 +00:00
|
|
|
{
|
2022-04-01 13:54:21 +00:00
|
|
|
var queueTasks = LoadFromCache();
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
queueTasks = DeleteOrphanCacheItem(queueTasks);
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
if (instanceId.HasValue)
|
2020-07-13 15:26:21 +00:00
|
|
|
{
|
2022-04-01 13:54:21 +00:00
|
|
|
queueTasks = queueTasks.Where(x => x.InstanceId == instanceId.Value);
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2022-02-01 14:51:29 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
foreach (var task in queueTasks)
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-02-23 19:42:34 +00:00
|
|
|
if (task.Publication == null)
|
2022-02-08 11:07:28 +00:00
|
|
|
{
|
2022-02-03 15:26:44 +00:00
|
|
|
task.Publication = GetPublication();
|
2022-02-08 11:07:28 +00:00
|
|
|
}
|
2022-02-03 15:26:44 +00:00
|
|
|
}
|
2020-10-02 07:19:02 +00:00
|
|
|
|
2022-03-25 16:15:28 +00:00
|
|
|
return queueTasks;
|
2022-02-03 15:26:44 +00:00
|
|
|
}
|
|
|
|
|
2022-03-25 18:00:43 +00:00
|
|
|
public IEnumerable<T> GetAllTasks<T>() where T : DistributedTask
|
2022-02-03 15:26:44 +00:00
|
|
|
{
|
2022-04-01 13:54:21 +00:00
|
|
|
return GetAllTasks().Select(x => Map(x, _serviceProvider.GetService<T>()));
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2022-02-03 15:26:44 +00:00
|
|
|
|
2022-03-25 18:00:43 +00:00
|
|
|
public T PeekTask<T>(string id) where T : DistributedTask
|
2022-04-01 13:54:21 +00:00
|
|
|
{
|
2022-03-25 18:00:43 +00:00
|
|
|
var taskById = GetAllTasks().FirstOrDefault(x => x.Id == id);
|
2020-10-02 07:19:02 +00:00
|
|
|
|
2022-04-14 19:23:57 +00:00
|
|
|
if (taskById == null)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
2022-02-01 14:51:29 +00:00
|
|
|
|
2022-03-25 16:15:28 +00:00
|
|
|
return Map(taskById, _serviceProvider.GetService<T>());
|
2022-02-03 15:26:44 +00:00
|
|
|
}
|
2022-02-01 14:51:29 +00:00
|
|
|
|
2022-03-25 18:00:43 +00:00
|
|
|
public void DequeueTask(string id)
|
2022-02-08 11:07:28 +00:00
|
|
|
{
|
2022-03-25 18:00:43 +00:00
|
|
|
var queueTasks = GetAllTasks().ToList();
|
2022-03-25 16:15:28 +00:00
|
|
|
|
2022-04-14 19:23:57 +00:00
|
|
|
if (!queueTasks.Exists(x => x.Id == id))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2022-02-01 14:51:29 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
_cancellationCacheNotify.Publish(new DistributedTaskCancelation() { Id = id }, CacheNotifyAction.Remove);
|
|
|
|
|
2022-03-25 16:15:28 +00:00
|
|
|
queueTasks = queueTasks.FindAll(x => x.Id != id);
|
|
|
|
|
2022-04-01 07:10:15 +00:00
|
|
|
if (queueTasks.Count == 0)
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-04-01 07:10:15 +00:00
|
|
|
_distributedCache.Remove(_name);
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2022-04-01 07:10:15 +00:00
|
|
|
else
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-04-01 13:54:21 +00:00
|
|
|
SaveToCache(queueTasks);
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2022-03-25 18:00:43 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
_logger.TraceFormat("DequeueTask '{DistributedTaskId}' by instanse id '{InstanceId}'", id, INSTANCE_ID);
|
2022-03-25 18:00:43 +00:00
|
|
|
|
2022-02-08 11:07:28 +00:00
|
|
|
}
|
2022-02-03 15:26:44 +00:00
|
|
|
|
|
|
|
private void OnCompleted(Task task, string id)
|
|
|
|
{
|
2022-03-25 18:00:43 +00:00
|
|
|
var distributedTask = GetAllTasks().FirstOrDefault(x => x.Id == id);
|
2022-02-03 15:26:44 +00:00
|
|
|
if (distributedTask != null)
|
2020-08-07 15:42:58 +00:00
|
|
|
{
|
2022-02-03 15:26:44 +00:00
|
|
|
distributedTask.Status = DistributedTaskStatus.Completed;
|
2022-04-01 13:54:21 +00:00
|
|
|
if (task.Exception != null)
|
|
|
|
{
|
2022-04-14 19:42:15 +00:00
|
|
|
distributedTask.Exception = task.Exception;
|
2022-04-01 13:54:21 +00:00
|
|
|
}
|
2022-02-08 11:07:28 +00:00
|
|
|
if (task.IsFaulted)
|
|
|
|
{
|
|
|
|
distributedTask.Status = DistributedTaskStatus.Failted;
|
|
|
|
}
|
2022-02-01 14:51:29 +00:00
|
|
|
|
2022-02-08 11:07:28 +00:00
|
|
|
if (task.IsCanceled)
|
|
|
|
{
|
|
|
|
distributedTask.Status = DistributedTaskStatus.Canceled;
|
|
|
|
}
|
2020-08-07 15:42:58 +00:00
|
|
|
|
2022-03-22 12:10:05 +00:00
|
|
|
_cancelations.TryRemove(id, out _);
|
2020-02-07 11:34:25 +00:00
|
|
|
|
2022-02-03 15:26:44 +00:00
|
|
|
distributedTask.PublishChanges();
|
|
|
|
}
|
|
|
|
}
|
2020-02-07 11:34:25 +00:00
|
|
|
|
2022-02-03 15:26:44 +00:00
|
|
|
private Action<DistributedTask> GetPublication()
|
|
|
|
{
|
2022-03-25 18:00:43 +00:00
|
|
|
return (task) =>
|
2022-02-03 15:26:44 +00:00
|
|
|
{
|
2022-03-25 18:00:43 +00:00
|
|
|
var queueTasks = GetAllTasks().ToList().FindAll(x => x.Id != task.Id);
|
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
task.LastModifiedOn = DateTime.UtcNow;
|
2019-08-16 08:44:03 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
queueTasks.Add(task);
|
2022-03-25 18:00:43 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
SaveToCache(queueTasks);
|
2022-03-25 18:00:43 +00:00
|
|
|
|
|
|
|
_logger.TraceFormat("Publication DistributedTask '{DistributedTaskId}' by instanse id '{InstanceId}' ", task.Id, task.InstanceId);
|
2022-02-03 15:26:44 +00:00
|
|
|
};
|
2020-08-06 10:53:34 +00:00
|
|
|
}
|
2022-03-25 16:15:28 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
|
|
|
|
private void SaveToCache(IEnumerable<DistributedTask> queueTasks)
|
|
|
|
{
|
|
|
|
using var ms = new MemoryStream();
|
|
|
|
|
|
|
|
Serializer.Serialize(ms, queueTasks);
|
|
|
|
|
|
|
|
_distributedCache.Set(_name, ms.ToArray(), new DistributedCacheEntryOptions
|
|
|
|
{
|
|
|
|
SlidingExpiration = TimeSpan.FromMinutes(15)
|
|
|
|
});
|
|
|
|
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2020-08-06 10:53:34 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
private IEnumerable<DistributedTask> LoadFromCache()
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-04-01 13:54:21 +00:00
|
|
|
var serializedObject = _distributedCache.Get(_name);
|
|
|
|
|
2022-04-14 19:23:57 +00:00
|
|
|
if (serializedObject == null)
|
|
|
|
{
|
|
|
|
return new List<DistributedTask>();
|
|
|
|
}
|
2022-04-01 13:54:21 +00:00
|
|
|
|
|
|
|
using var ms = new MemoryStream(serializedObject);
|
|
|
|
|
|
|
|
return Serializer.Deserialize<List<DistributedTask>>(ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
private IEnumerable<DistributedTask> DeleteOrphanCacheItem(IEnumerable<DistributedTask> queueTasks)
|
2022-02-03 15:26:44 +00:00
|
|
|
{
|
2022-04-14 19:23:57 +00:00
|
|
|
if (!queueTasks.Any())
|
|
|
|
{
|
|
|
|
return queueTasks;
|
|
|
|
}
|
2022-04-01 13:54:21 +00:00
|
|
|
|
|
|
|
var orphans = queueTasks.Where(IsOrphanCacheItem);
|
|
|
|
|
2022-04-14 19:23:57 +00:00
|
|
|
if (!orphans.Any())
|
|
|
|
{
|
|
|
|
return queueTasks;
|
|
|
|
}
|
2022-04-01 13:54:21 +00:00
|
|
|
|
|
|
|
queueTasks = queueTasks.Except(queueTasks);
|
2021-05-19 08:31:50 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
SaveToCache(queueTasks);
|
2022-02-01 14:51:29 +00:00
|
|
|
|
2022-04-01 13:54:21 +00:00
|
|
|
return queueTasks;
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool IsOrphanCacheItem(DistributedTask obj)
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-04-01 13:54:21 +00:00
|
|
|
return obj.LastModifiedOn.AddSeconds(_timeUntilUnregisterInSeconds) < DateTime.UtcNow;
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2021-05-13 08:23:44 +00:00
|
|
|
|
2020-08-06 10:53:34 +00:00
|
|
|
|
2022-03-25 16:15:28 +00:00
|
|
|
/// <summary>
|
2022-03-26 13:31:13 +00:00
|
|
|
/// Maps the source object to destination object.
|
2022-03-25 16:15:28 +00:00
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="T">Type of destination object.</typeparam>
|
|
|
|
/// <typeparam name="TU">Type of source object.</typeparam>
|
|
|
|
/// <param name="destination">Destination object.</param>
|
|
|
|
/// <param name="source">Source object.</param>
|
|
|
|
/// <returns>Updated destination object.</returns>
|
|
|
|
private T Map<T, TU>(TU source, T destination)
|
2022-04-14 19:42:15 +00:00
|
|
|
{
|
2022-03-25 16:15:28 +00:00
|
|
|
destination.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
|
|
|
|
.ToList()
|
|
|
|
.ForEach(field =>
|
|
|
|
{
|
|
|
|
var sf = source.GetType().GetField(field.Name, BindingFlags.NonPublic | BindingFlags.Instance);
|
|
|
|
|
|
|
|
if (sf != null)
|
|
|
|
{
|
|
|
|
var value = sf.GetValue(source);
|
|
|
|
destination.GetType().GetField(field.Name, BindingFlags.NonPublic | BindingFlags.Instance).SetValue(destination, value);
|
|
|
|
}
|
2022-04-14 19:42:15 +00:00
|
|
|
});
|
2020-08-06 10:53:34 +00:00
|
|
|
|
2022-03-25 16:15:28 +00:00
|
|
|
destination.GetType().GetProperties().Where(p => p.CanWrite == true && !p.GetIndexParameters().Any())
|
|
|
|
.ToList()
|
|
|
|
.ForEach(prop =>
|
|
|
|
{
|
|
|
|
var sp = source.GetType().GetProperty(prop.Name);
|
|
|
|
if (sp != null)
|
|
|
|
{
|
|
|
|
var value = sp.GetValue(source, null);
|
|
|
|
destination.GetType().GetProperty(prop.Name).SetValue(destination, value, null);
|
2022-04-14 19:42:15 +00:00
|
|
|
}
|
2022-03-25 16:15:28 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return destination;
|
|
|
|
}
|
|
|
|
|
2022-02-08 11:07:28 +00:00
|
|
|
}
|