This commit is contained in:
@@ -20,7 +20,7 @@ Done!
|
||||
License agreement page for subscription vs perpetual
|
||||
("Quickly, quickly, there's no time" must use a new format as this is a subscription "SERVICE" not a software product so maybe look at quickbooks license or service agreement I guess it would be called)
|
||||
Must be clear customer is responsible for their data and must remain within reasonable usage levels or we will cancel the service
|
||||
|
||||
TODO: must change the "View license agreement" link in About form to "View service agreement" and use Service agreement text to describe it
|
||||
|
||||
- Launch a trialing server, can start small and work up but keep all users on it so to save money and not any of our own corporate infrastructure servers
|
||||
"All free trial subscriptions are located in New York data center. Paid subscriptions can be in any of the following data centers of your choice ...blah blah blah."
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
//------------
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace AyaNova.Biz
|
||||
Sleeping = 1,
|
||||
Running = 2,
|
||||
Completed = 3,
|
||||
Failed = 4
|
||||
Failed = 4,
|
||||
CancelRequested = 5
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
26
server/AyaNova/models/dto/JobProgress.cs
Normal file
26
server/AyaNova/models/dto/JobProgress.cs
Normal 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; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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!!!!
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user