This commit is contained in:
2022-09-27 23:06:28 +00:00
parent 1d706b4bb7
commit 153978785c
9 changed files with 142 additions and 7 deletions

View File

@@ -99,7 +99,20 @@ namespace AyaNova.Api.Controllers
return Ok(ApiOkResponse.Response(await JobsBiz.GetJobStatusAsync(gid)));
}
/// <summary>
/// Get current job status and progress for a job
/// </summary>
/// <param name="gid"></param>
/// <returns>A single job's current status and progress</returns>
[HttpGet("progress/{gid}")]
public async Task<IActionResult> GetJobProgress([FromRoute] Guid gid)
{
if (!ModelState.IsValid)
return BadRequest(new ApiErrorResponse(ModelState));
return Ok(ApiOkResponse.Response(await JobsBiz.GetJobProgressAsync(gid)));
}
/// <summary>
@@ -240,6 +253,23 @@ namespace AyaNova.Api.Controllers
}
/// <summary>
/// Request cancellation of Job. Not all jobs can be cancelled.
/// </summary>
/// <param name="gid"></param>
/// <returns>Accepted</returns>
[HttpPost("request-cancel/{gid}")]
public async Task<IActionResult> RequestCancelJob([FromRoute] Guid gid)
{
if (!ModelState.IsValid)
return BadRequest(new ApiErrorResponse(ModelState));
await JobsBiz.RequestCancelAsync(gid);
return Accepted();
}
//------------

View File

@@ -596,10 +596,29 @@ namespace AyaNova.Biz
else
idList = await ct.Customer.AsNoTracking().Select(z => z.Id).ToListAsync();
bool SaveIt = false;
//case 4192
TimeSpan ProgressAndCancelCheckSpan = new TimeSpan(0, 0, ServerBootConfig.JOB_PROGRESS_UPDATE_AND_CANCEL_CHECK_SECONDS);
DateTime LastProgressCheck = DateTime.UtcNow.Subtract(new TimeSpan(1, 1, 1, 1, 1));
var TotalRecords = idList.LongCount();
long CurrentRecord = -1;
foreach (long id in idList)
{
try
{
//Update progress / cancel requested?
CurrentRecord++;
if (DateUtil.IsAfterDuration(LastProgressCheck, ProgressAndCancelCheckSpan))
{
await JobsBiz.UpdateJobProgressAsync(job.GId, $"{CurrentRecord}/{TotalRecords}");
if (await JobsBiz.GetJobStatusAsync(job.GId) == JobStatus.CancelRequested)
{
break;
}
}
SaveIt = false;
ClearErrors();
Customer o = null;
@@ -635,7 +654,7 @@ namespace AyaNova.Biz
FailedObjectCount++;
}
}
//TEMPORARY MEASURE AWAITING BETTER SOLUTION AND CANCELLABLE EXTENSION JOBS
//TEMPORARY MEASURE AWAITING BETTER SOLUTION AND CANCELLABLE EXTENSION JOBS
//delay so we're not tying up all the resources in a tight loop
await Task.Delay(AyaNova.Util.ServerBootConfig.JOB_OBJECT_HANDLE_BATCH_JOB_LOOP_DELAY);
}

View File

@@ -11,7 +11,8 @@ namespace AyaNova.Biz
Sleeping = 1,
Running = 2,
Completed = 3,
Failed = 4
Failed = 4,
CancelRequested = 5
}

View File

@@ -73,6 +73,16 @@ namespace AyaNova.Biz
}
}
/// <summary>
/// Request the cancellation of a job, not all jobs honour this
/// </summary>
/// <param name="jobId"></param>
internal static async Task RequestCancelAsync(Guid jobId)
{
await UpdateJobStatusAsync(jobId, JobStatus.CancelRequested);
await LogJobAsync(jobId, "LT:Cancel");
}
/// <summary>
/// Remove the job and it's logs
@@ -152,6 +162,37 @@ namespace AyaNova.Biz
return o.JobStatus;
}
}
/// <summary>
/// Update the progress of a job
/// </summary>
/// <param name="jobId"></param>
/// <param name="progress"></param>
internal static async Task UpdateJobProgressAsync(Guid jobId, string progress)
{
using (AyContext ct = ServiceProviderProvider.DBContext)
{
var oFromDb = await ct.OpsJob.SingleOrDefaultAsync(z => z.GId == jobId);
if (oFromDb == null) return;
oFromDb.Progress = progress;
await ct.SaveChangesAsync();
}
}
/// <summary>
/// Get the progress and status of a job
/// </summary>
/// <param name="jobId"></param>
internal static async Task<JobProgress> GetJobProgressAsync(Guid jobId)
{
using (AyContext ct = ServiceProviderProvider.DBContext)
{
var o = await ct.OpsJob.AsNoTracking().SingleOrDefaultAsync(z => z.GId == jobId);
if (o == null) return new JobProgress() { JobStatus = JobStatus.Absent, Progress = string.Empty };
return new JobProgress() { JobStatus = o.JobStatus, Progress = o.Progress };
}
}
#endregion Job ops
#region PROCESSOR

View File

@@ -39,6 +39,7 @@ namespace AyaNova.Models
/// </summary>
public string JobInfo { get; set; }//json as string of any required extra info for job
public string Progress {get;set;}//any type of text digestible by client showing progress of job, typically just a string i.e. "133/344"
public OpsJob()
{
@@ -53,6 +54,7 @@ namespace AyaNova.Models
AType = AyaType.NoType;
JobStatus = JobStatus.Sleeping;
JobInfo = null;
Progress=string.Empty;
}

View File

@@ -0,0 +1,26 @@
using AyaNova.Biz;
using System;
namespace AyaNova.Models
{
/// <summary>
/// Job Progress
/// </summary>
public class JobProgress
{
/// <summary>
/// Progress string
/// </summary>
/// <returns>string</returns>
public string Progress { get; set; }
/// <summary>
/// Status of the job
/// </summary>
/// <returns>Job status</returns>
public JobStatus JobStatus { get; set; }
}
}

View File

@@ -20,9 +20,9 @@ namespace AyaNova.Util
/////////// CHANGE THIS ON NEW SCHEMA UPDATE ////////////////////
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImportingAsync WHEN NEW TABLES ADDED!!!!
private const int DESIRED_SCHEMA_LEVEL = 7;
private const int DESIRED_SCHEMA_LEVEL = 8;
internal const long EXPECTED_COLUMN_COUNT = 1377;
internal const long EXPECTED_COLUMN_COUNT = 1378;
internal const long EXPECTED_INDEX_COUNT = 161;
internal const long EXPECTED_CHECK_CONSTRAINTS = 561;
internal const long EXPECTED_FOREIGN_KEY_CONSTRAINTS = 204;
@@ -1571,6 +1571,21 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
}
//////////////////////////////////////////////////
//
// 8.0.13 additions for job feedback
//
if (currentSchema < 8)
{
LogUpdateMessage(log);
await ExecQueryAsync("ALTER TABLE aopsjob ADD column progress TEXT");
await SetSchemaLevelAsync(++currentSchema);
}
//#########################################
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!!

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.Configuration;
@@ -15,7 +16,7 @@ namespace AyaNova.Util
//STATIC HARD CODED COMPILE TIME DEFAULTS NOT SET THROUGH CONFIG
internal const int FAILED_AUTH_DELAY = 3000;//ms
internal const int JOB_OBJECT_HANDLE_BATCH_JOB_LOOP_DELAY = 200;//ms this delay is a temporary measure to ensure super big time consuming batch jobs don't use all server CPU resources
internal const int JOB_PROGRESS_UPDATE_AND_CANCEL_CHECK_SECONDS = 15;//seconds between progress updates and checks for cancellation of long running jobs
//UPLOAD LIMITS 1048576 = 1MiB for testing 10737420000 10737418240 10,737,418,240
internal const long MAX_ATTACHMENT_UPLOAD_BYTES = 10737420000;//slight bit of overage as 10737418241=10GiB