Background task execution intervals are now user configurable (#209)
* Store background task intervals in database * Background task intervals are now user customisable
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -10,6 +11,7 @@ using gaseous_server.Classes;
|
|||||||
using gaseous_server.Classes.Metadata;
|
using gaseous_server.Classes.Metadata;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Razor.Hosting;
|
||||||
|
|
||||||
namespace gaseous_server.Controllers
|
namespace gaseous_server.Controllers
|
||||||
{
|
{
|
||||||
@@ -99,6 +101,75 @@ namespace gaseous_server.Controllers
|
|||||||
return File(bytes, "text/javascript");
|
return File(bytes, "text/javascript");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpGet]
|
||||||
|
[Route("Settings/BackgroundTasks/Intervals")]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public ActionResult GetBackgroundTasks()
|
||||||
|
{
|
||||||
|
Dictionary<string, BackgroundTaskItem> Intervals = new Dictionary<string, BackgroundTaskItem>();
|
||||||
|
Intervals.Add(ProcessQueue.QueueItemType.SignatureIngestor.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.SignatureIngestor));
|
||||||
|
Intervals.Add(ProcessQueue.QueueItemType.TitleIngestor.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.TitleIngestor));
|
||||||
|
Intervals.Add(ProcessQueue.QueueItemType.MetadataRefresh.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.MetadataRefresh));
|
||||||
|
Intervals.Add(ProcessQueue.QueueItemType.OrganiseLibrary.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.OrganiseLibrary));
|
||||||
|
Intervals.Add(ProcessQueue.QueueItemType.LibraryScan.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.LibraryScan));
|
||||||
|
Intervals.Add(ProcessQueue.QueueItemType.Rematcher.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.Rematcher));
|
||||||
|
Intervals.Add(ProcessQueue.QueueItemType.Maintainer.ToString(), new BackgroundTaskItem(ProcessQueue.QueueItemType.Maintainer));
|
||||||
|
|
||||||
|
return Ok(Intervals);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapToApiVersion("1.0")]
|
||||||
|
[MapToApiVersion("1.1")]
|
||||||
|
[HttpPost]
|
||||||
|
[Route("Settings/BackgroundTasks/Intervals")]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public ActionResult SetBackgroundTasks(Dictionary<string, int> Intervals)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, int> Interval in Intervals)
|
||||||
|
{
|
||||||
|
if (Enum.IsDefined(typeof(ProcessQueue.QueueItemType), Interval.Key))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BackgroundTaskItem taskItem = new BackgroundTaskItem(
|
||||||
|
(ProcessQueue.QueueItemType)Enum.Parse(typeof(ProcessQueue.QueueItemType), Interval.Key)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Interval.Value >= taskItem.MinimumAllowedValue)
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Information, "Update Background Task", "Updating task " + Interval.Key + " with new interval " + Interval.Value);
|
||||||
|
|
||||||
|
Config.SetSetting("Interval_" + Interval.Key, Interval.Value.ToString());
|
||||||
|
|
||||||
|
// update existing process
|
||||||
|
foreach (ProcessQueue.QueueItem item in ProcessQueue.QueueItems)
|
||||||
|
{
|
||||||
|
if (item.ItemType.ToString().ToLower() == Interval.Key.ToLower())
|
||||||
|
{
|
||||||
|
item.Interval = Interval.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Interval " + Interval.Value + " for task " + Interval.Key + " is below the minimum allowed value of " + taskItem.MinimumAllowedValue + ". Skipping.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// task name not defined
|
||||||
|
Logging.Log(Logging.LogType.Warning, "Update Background Task", "Task " + Interval.Key + " is not user definable. Skipping.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
private SystemInfo.PathItem GetDisk(string Path)
|
private SystemInfo.PathItem GetDisk(string Path)
|
||||||
{
|
{
|
||||||
SystemInfo.PathItem pathItem = new SystemInfo.PathItem {
|
SystemInfo.PathItem pathItem = new SystemInfo.PathItem {
|
||||||
@@ -139,4 +210,63 @@ namespace gaseous_server.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BackgroundTaskItem
|
||||||
|
{
|
||||||
|
public BackgroundTaskItem(ProcessQueue.QueueItemType TaskName)
|
||||||
|
{
|
||||||
|
this.Task = TaskName.ToString();
|
||||||
|
|
||||||
|
switch (TaskName)
|
||||||
|
{
|
||||||
|
case ProcessQueue.QueueItemType.SignatureIngestor:
|
||||||
|
this.DefaultInterval = 60;
|
||||||
|
this.MinimumAllowedValue = 20;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.TitleIngestor:
|
||||||
|
this.DefaultInterval = 1;
|
||||||
|
this.MinimumAllowedValue = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.MetadataRefresh:
|
||||||
|
this.DefaultInterval = 360;
|
||||||
|
this.MinimumAllowedValue = 360;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.OrganiseLibrary:
|
||||||
|
this.DefaultInterval = 1440;
|
||||||
|
this.MinimumAllowedValue = 120;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.LibraryScan:
|
||||||
|
this.DefaultInterval = 1440;
|
||||||
|
this.MinimumAllowedValue = 120;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.Rematcher:
|
||||||
|
this.DefaultInterval = 1440;
|
||||||
|
this.MinimumAllowedValue = 360;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessQueue.QueueItemType.Maintainer:
|
||||||
|
this.DefaultInterval = 10080;
|
||||||
|
this.MinimumAllowedValue = 10080;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Exception("Invalid task");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Task { get; set; }
|
||||||
|
public int Interval {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return int.Parse(Config.ReadSetting("Interval_" + Task, DefaultInterval.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int DefaultInterval { get; set; }
|
||||||
|
public int MinimumAllowedValue { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
@@ -67,7 +67,17 @@ namespace gaseous_server
|
|||||||
return LastRunTime.AddMinutes(Interval);
|
return LastRunTime.AddMinutes(Interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public int Interval => _Interval;
|
public int Interval
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _Interval;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_Interval = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
public string LastResult => _LastResult;
|
public string LastResult => _LastResult;
|
||||||
public string? LastError => _LastError;
|
public string? LastError => _LastError;
|
||||||
public bool Force => _ForceExecute;
|
public bool Force => _ForceExecute;
|
||||||
|
@@ -8,6 +8,15 @@
|
|||||||
</table>
|
</table>
|
||||||
<div style="text-align: right;"><button id="settings_newlibrary" onclick="showSubDialog('librarynew');">New Library</button></div>
|
<div style="text-align: right;"><button id="settings_newlibrary" onclick="showSubDialog('librarynew');">New Library</button></div>
|
||||||
|
|
||||||
|
<h2>Advanced Settings</h2>
|
||||||
|
<p><strong>Warning</strong> Do not modify the below settings unless you know what you're doing.</p>
|
||||||
|
<h3>Background Task Timers</h3>
|
||||||
|
<p>All intervals are in minutes.</p>
|
||||||
|
<table id="settings_tasktimers" class="romtable" style="width: 100%;" cellspacing="0">
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<div style="text-align: right;"><button id="settings_tasktimers_default" onclick="defaultTaskTimers();">Reset to Default</button><button id="settings_tasktimers_new" onclick="saveTaskTimers();">Save</button></div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function drawLibrary() {
|
function drawLibrary() {
|
||||||
ajaxCall(
|
ajaxCall(
|
||||||
@@ -59,5 +68,67 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBackgroundTaskTimers() {
|
||||||
|
ajaxCall(
|
||||||
|
'/api/v1/System/Settings/BackgroundTasks/Intervals',
|
||||||
|
'GET',
|
||||||
|
function(result) {
|
||||||
|
var targetTable = document.getElementById('settings_tasktimers');
|
||||||
|
targetTable.innerHTML = '';
|
||||||
|
|
||||||
|
targetTable.appendChild(
|
||||||
|
createTableRow(true, ['Background Task', 'Timer Interval', 'Default Interval', 'Minimum Allowed Interval'])
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(result)) {
|
||||||
|
var newTableRow = createTableRow(
|
||||||
|
false,
|
||||||
|
[
|
||||||
|
GetTaskFriendlyName(value.task),
|
||||||
|
'<input id="settings_tasktimers_' + value.task + '" name="settings_tasktimers_values" data-name="' + value.task + '" data-default="' + value.defaultInterval + '" type="number" placeholder="0" min="' + value.minimumAllowedValue + '" value="' + value.interval + '" />',
|
||||||
|
value.defaultInterval,
|
||||||
|
value.minimumAllowedValue
|
||||||
|
],
|
||||||
|
'romrow',
|
||||||
|
'romcell'
|
||||||
|
);
|
||||||
|
targetTable.appendChild(newTableRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveTaskTimers() {
|
||||||
|
var timerValues = document.getElementsByName('settings_tasktimers_values');
|
||||||
|
|
||||||
|
var model = {};
|
||||||
|
for (var i = 0; i < timerValues.length; i++) {
|
||||||
|
model[timerValues[i].getAttribute('data-name')] = timerValues[i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ajaxCall(
|
||||||
|
'/api/v1/System/Settings/BackgroundTasks/Intervals',
|
||||||
|
'POST',
|
||||||
|
function(result) {
|
||||||
|
getBackgroundTaskTimers();
|
||||||
|
},
|
||||||
|
function(error) {
|
||||||
|
getBackgroundTaskTimers();
|
||||||
|
},
|
||||||
|
JSON.stringify(model)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultTaskTimers() {
|
||||||
|
var timerValues = document.getElementsByName('settings_tasktimers_values');
|
||||||
|
|
||||||
|
for (var i = 0; i < timerValues.length; i++) {
|
||||||
|
timerValues[i].value = timerValues[i].getAttribute('data-default');
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTaskTimers();
|
||||||
|
}
|
||||||
|
|
||||||
drawLibrary();
|
drawLibrary();
|
||||||
|
getBackgroundTaskTimers();
|
||||||
</script>
|
</script>
|
@@ -34,34 +34,8 @@
|
|||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
for (var i = 0; i < result.length; i++) {
|
for (var i = 0; i < result.length; i++) {
|
||||||
var itemTypeName;
|
var itemTypeName = GetTaskFriendlyName(result[i].itemType, result[i].options);
|
||||||
switch (result[i].itemType) {
|
|
||||||
case 'SignatureIngestor':
|
|
||||||
itemTypeName = "Signature import";
|
|
||||||
break;
|
|
||||||
case 'TitleIngestor':
|
|
||||||
itemTypeName = "Title import";
|
|
||||||
break;
|
|
||||||
case 'MetadataRefresh':
|
|
||||||
itemTypeName = "Metadata refresh"
|
|
||||||
break;
|
|
||||||
case 'OrganiseLibrary':
|
|
||||||
itemTypeName = "Organise library";
|
|
||||||
break;
|
|
||||||
case 'LibraryScan':
|
|
||||||
itemTypeName = "Library scan";
|
|
||||||
break;
|
|
||||||
case 'CollectionCompiler':
|
|
||||||
itemTypeName = "Compress collection id: " + result[i].options;
|
|
||||||
break;
|
|
||||||
case 'BackgroundDatabaseUpgrade':
|
|
||||||
itemTypeName = "Background database upgrade";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
itemTypeName = result[i].itemType;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var itemStateName;
|
var itemStateName;
|
||||||
var itemLastStart;
|
var itemLastStart;
|
||||||
if (result[i].isBlocked == false) {
|
if (result[i].isBlocked == false) {
|
||||||
|
@@ -388,4 +388,25 @@ function CreateBadge(BadgeText, ColourOverride) {
|
|||||||
badgeItem.style.borderColor = ColourOverride;
|
badgeItem.style.borderColor = ColourOverride;
|
||||||
}
|
}
|
||||||
return badgeItem;
|
return badgeItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetTaskFriendlyName(TaskName, options) {
|
||||||
|
switch (TaskName) {
|
||||||
|
case 'SignatureIngestor':
|
||||||
|
return "Signature import";
|
||||||
|
case 'TitleIngestor':
|
||||||
|
return "Title import";
|
||||||
|
case 'MetadataRefresh':
|
||||||
|
return "Metadata refresh";
|
||||||
|
case 'OrganiseLibrary':
|
||||||
|
return "Organise library";
|
||||||
|
case 'LibraryScan':
|
||||||
|
return "Library scan";
|
||||||
|
case 'CollectionCompiler':
|
||||||
|
return "Compress collection id: " + options;
|
||||||
|
case 'BackgroundDatabaseUpgrade':
|
||||||
|
return "Background database upgrade";
|
||||||
|
default:
|
||||||
|
return TaskName;
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user