This commit is contained in:
@@ -101,6 +101,7 @@ namespace AyaNova.Api.Controllers
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get Operations log for a job
|
/// Get Operations log for a job
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -195,50 +195,50 @@ namespace AyaNova.Api.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Render Report
|
// /// Render Report
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <param name="reportRequest">report id and object id values for object type specified in report template</param>
|
// /// <param name="reportRequest">report id and object id values for object type specified in report template</param>
|
||||||
/// <param name="apiVersion">From route path</param>
|
// /// <param name="apiVersion">From route path</param>
|
||||||
/// <returns>downloadable pdf name</returns>
|
// /// <returns>downloadable pdf name</returns>
|
||||||
[HttpPost("render")]
|
// [HttpPost("render")]
|
||||||
public async Task<IActionResult> RenderReport([FromBody] DataListReportRequest reportRequest, ApiVersion apiVersion)
|
// public async Task<IActionResult> RenderReport([FromBody] DataListReportRequest reportRequest, ApiVersion apiVersion)
|
||||||
{
|
// {
|
||||||
if (!serverState.IsOpen)
|
// if (!serverState.IsOpen)
|
||||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
// return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||||
|
|
||||||
//this is done by a recurring JOB now so no longer needed here
|
// //this is done by a recurring JOB now so no longer needed here
|
||||||
// //check for an kill any expired prior renders stuck around
|
// // //check for an kill any expired prior renders stuck around
|
||||||
// Util.ReportRenderManager.KillExpiredRenders(log);
|
// // Util.ReportRenderManager.KillExpiredRenders(log);
|
||||||
|
|
||||||
ReportBiz biz = ReportBiz.GetBiz(ct, HttpContext);
|
// ReportBiz biz = ReportBiz.GetBiz(ct, HttpContext);
|
||||||
if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType))
|
// if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType))
|
||||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
// return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||||
if (!ModelState.IsValid)
|
// if (!ModelState.IsValid)
|
||||||
return BadRequest(new ApiErrorResponse(ModelState));
|
// return BadRequest(new ApiErrorResponse(ModelState));
|
||||||
|
|
||||||
var httpConnectionFeature = HttpContext.Features.Get<IHttpConnectionFeature>();
|
// var httpConnectionFeature = HttpContext.Features.Get<IHttpConnectionFeature>();
|
||||||
var API_URL = $"http://127.0.0.1:{httpConnectionFeature.LocalPort}/api/v8/";
|
// var API_URL = $"http://127.0.0.1:{httpConnectionFeature.LocalPort}/api/v8/";
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
var result = await biz.RenderReport(reportRequest, DateTime.UtcNow.AddMinutes(ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT), API_URL);
|
// var result = await biz.RenderReport(reportRequest, DateTime.UtcNow.AddMinutes(ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT), API_URL);
|
||||||
if (string.IsNullOrWhiteSpace(result))
|
// if (string.IsNullOrWhiteSpace(result))
|
||||||
return BadRequest(new ApiErrorResponse(biz.Errors));
|
// return BadRequest(new ApiErrorResponse(biz.Errors));
|
||||||
else
|
// else
|
||||||
return Ok(ApiOkResponse.Response(result));
|
// return Ok(ApiOkResponse.Response(result));
|
||||||
}
|
// }
|
||||||
catch (ReportRenderTimeOutException)
|
// catch (ReportRenderTimeOutException)
|
||||||
{
|
// {
|
||||||
log.LogInformation($"Report render timeout, exceeded timeout setting of {ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT} minutes, report id: {reportRequest.ReportId}, record count:{reportRequest.SelectedRowIds.LongLength}, user:{UserNameFromContext.Name(HttpContext.Items)} ");
|
// log.LogInformation($"Report render timeout, exceeded timeout setting of {ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT} minutes, report id: {reportRequest.ReportId}, record count:{reportRequest.SelectedRowIds.LongLength}, user:{UserNameFromContext.Name(HttpContext.Items)} ");
|
||||||
return Ok(ApiOkResponse.Response(new { timeout = true, timeoutconfigminutes = ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT }));
|
// return Ok(ApiOkResponse.Response(new { timeout = true, timeoutconfigminutes = ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT }));
|
||||||
}
|
// }
|
||||||
catch (System.Exception ex)
|
// catch (System.Exception ex)
|
||||||
{
|
// {
|
||||||
//The Javascript evaluation stack trace can be in the message making it long and internalized,
|
// //The Javascript evaluation stack trace can be in the message making it long and internalized,
|
||||||
//however the info is useful as it can indicate exactly which function failed etc so sending it all back is best
|
// //however the info is useful as it can indicate exactly which function failed etc so sending it all back is best
|
||||||
return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, ex.Message));
|
// return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, ex.Message));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -267,6 +267,25 @@ namespace AyaNova.Api.Controllers
|
|||||||
return Accepted(new { JobId = result });
|
return Accepted(new { JobId = result });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt cancel render job
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gid"></param>
|
||||||
|
/// <returns>nothing</returns>
|
||||||
|
[HttpGet("request-cancel/{gid}")]
|
||||||
|
public async Task<IActionResult> RequestCancelJob([FromRoute] Guid gid)
|
||||||
|
{
|
||||||
|
if (!serverState.IsOpen)
|
||||||
|
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||||
|
ReportBiz biz = ReportBiz.GetBiz(ct, HttpContext);
|
||||||
|
if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType))
|
||||||
|
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return BadRequest(new ApiErrorResponse(ModelState));
|
||||||
|
await biz.CancelJob(gid);
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Download a rendered report
|
/// Download a rendered report
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ namespace AyaNova.Biz
|
|||||||
if (!KeepOnWorking()) return;
|
if (!KeepOnWorking()) return;
|
||||||
|
|
||||||
//Check for and kill stuck report rendering engine processes
|
//Check for and kill stuck report rendering engine processes
|
||||||
CoreJobReportRenderEngineProcessCleanup.DoWork();
|
await CoreJobReportRenderEngineProcessCleanup.DoWork();
|
||||||
if (!KeepOnWorking()) return;
|
if (!KeepOnWorking()) return;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using AyaNova.Util;
|
using AyaNova.Util;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AyaNova.Biz
|
namespace AyaNova.Biz
|
||||||
{
|
{
|
||||||
@@ -19,12 +19,12 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
public static void DoWork()
|
public static async Task DoWork()
|
||||||
{
|
{
|
||||||
if (DateUtil.IsAfterDuration(_lastRun, tsRunEvery))
|
if (DateUtil.IsAfterDuration(_lastRun, tsRunEvery))
|
||||||
{
|
{
|
||||||
log.LogDebug("Checking for expired processes");
|
log.LogDebug("Checking for expired processes");
|
||||||
Util.ReportRenderManager.KillExpiredRenders(log);
|
await Util.ReportRenderManager.KillExpiredRenders(log);
|
||||||
//FileUtil.CleanTemporaryFilesFolder(new TimeSpan(0,5,0));//erase any files found to be older than 5 minutes
|
//FileUtil.CleanTemporaryFilesFolder(new TimeSpan(0,5,0));//erase any files found to be older than 5 minutes
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
_lastRun = now;
|
_lastRun = now;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AyaNova.Biz;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace AyaNova.Util
|
namespace AyaNova.Util
|
||||||
@@ -21,16 +23,18 @@ namespace AyaNova.Util
|
|||||||
{
|
{
|
||||||
internal int ReporterProcessId { get; set; }
|
internal int ReporterProcessId { get; set; }
|
||||||
internal DateTime Expires { get; set; }
|
internal DateTime Expires { get; set; }
|
||||||
|
internal Guid JobId { get; set; }
|
||||||
|
|
||||||
internal ReportRenderInstanceInfo(int processId, DateTime expires)
|
internal ReportRenderInstanceInfo(Guid jobId, DateTime expires)
|
||||||
{
|
{
|
||||||
ReporterProcessId = processId;
|
JobId = jobId;
|
||||||
Expires = expires;
|
Expires = expires;
|
||||||
|
ReporterProcessId = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal static void KillExpiredRenders(ILogger log)
|
internal static async Task KillExpiredRenders(ILogger log)
|
||||||
{
|
{
|
||||||
log.LogDebug("Clear potential expired render jobs check");
|
log.LogDebug("Clear potential expired render jobs check");
|
||||||
//check for expired and remove
|
//check for expired and remove
|
||||||
@@ -40,35 +44,39 @@ namespace AyaNova.Util
|
|||||||
{
|
{
|
||||||
if (i.Expires < dtNow)
|
if (i.Expires < dtNow)
|
||||||
{
|
{
|
||||||
|
log.LogDebug($"attempting close of expired process {i.ReporterProcessId} for job {i.JobId}");
|
||||||
log.LogDebug($"attempting close of expired process {i.ReporterProcessId}");
|
await CloseRenderProcess(i, log);
|
||||||
|
|
||||||
ForceCloseProcess(i, log);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool ForceCloseProcess(ReportRenderInstanceInfo instance, ILogger log)
|
internal static async Task<bool> CloseRenderProcess(ReportRenderInstanceInfo instance, ILogger log)
|
||||||
{
|
{
|
||||||
log.LogDebug($"ForceCloseProcess on report render instance id {instance.ReporterProcessId} expired {instance.Expires.ToString()} utc");
|
log.LogDebug($"ForceCloseProcess on report render instance id {instance.ReporterProcessId} expired {instance.Expires.ToString()} utc");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var p = Process.GetProcessById(instance.ReporterProcessId);
|
//either way, clear the job so the client gets informed
|
||||||
|
await JobsBiz.LogJobAsync(instance.JobId, $"rendererror:timeout,{ServerBootConfig.AYANOVA_REPORT_RENDERING_TIMEOUT}");//parseable for print client
|
||||||
|
await JobsBiz.UpdateJobStatusAsync(instance.JobId, JobStatus.Failed);
|
||||||
|
|
||||||
if (p != null)
|
if (instance.ReporterProcessId != -1)//if a job doesn't have a process id yet it will be -1
|
||||||
{
|
{
|
||||||
//we have an existing process
|
var p = Process.GetProcessById(instance.ReporterProcessId);
|
||||||
//try to kill it
|
if (p != null)
|
||||||
p.Kill(true);
|
|
||||||
if (p.HasExited == false)
|
|
||||||
{
|
{
|
||||||
log.LogWarning($"Expired report render instance id {instance.ReporterProcessId} could not be force closed");
|
//we have an existing process
|
||||||
return false;//can't kill it so can't free up a slot
|
//try to kill it
|
||||||
|
p.Kill(true);
|
||||||
|
if (p.HasExited == false)
|
||||||
|
{
|
||||||
|
log.LogWarning($"Expired report render instance id {instance.ReporterProcessId} could not be force closed");
|
||||||
|
return false;//can't kill it so can't free up a slot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//remove it from the list, it's either gone or killed at this point
|
//remove it from the list, it's either gone or killed at this point
|
||||||
//this would not be unexpected since it will normally just close on it's own
|
//this would not be unexpected since it will normally just close on it's own
|
||||||
//at the finally in render report
|
//at the finally block in render report
|
||||||
_baginstances.TryTake(out instance);
|
_baginstances.TryTake(out instance);
|
||||||
return true;//process that was there is now not there so while not perfect system we will consider it free
|
return true;//process that was there is now not there so while not perfect system we will consider it free
|
||||||
|
|
||||||
@@ -83,21 +91,61 @@ namespace AyaNova.Util
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void AddProcess(int processId, DateTime expires, ILogger log)
|
|
||||||
{
|
|
||||||
log.LogDebug($"AddProcess - {processId} to the collection");
|
|
||||||
_baginstances.Add(new ReportRenderInstanceInfo(processId, expires));
|
|
||||||
|
|
||||||
log.LogInformation($"AddProcess - there are currently {_baginstances.Count} instances in the collection");
|
internal static void AddJob(Guid jobId, DateTime expires, ILogger log)
|
||||||
|
{
|
||||||
|
log.LogDebug($"AddJob - {jobId} to the collection");
|
||||||
|
_baginstances.Add(new ReportRenderInstanceInfo(jobId, expires));
|
||||||
|
|
||||||
|
log.LogInformation($"AddJob - there are currently {_baginstances.Count} instances in the collection");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void RemoveProcess(int processId, ILogger log)
|
|
||||||
|
internal static void SetProcess(Guid jobId, int processId, ILogger log)
|
||||||
|
{
|
||||||
|
log.LogDebug($"SetProcess - setting {jobId} to render process id {processId}");
|
||||||
|
foreach (var i in _baginstances)
|
||||||
|
{
|
||||||
|
if (i.JobId == jobId)
|
||||||
|
{
|
||||||
|
i.ReporterProcessId = processId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task RemoveJob(Guid jobId, ILogger log)
|
||||||
|
{
|
||||||
|
foreach (var i in _baginstances)
|
||||||
|
{
|
||||||
|
if (i.JobId == jobId)
|
||||||
|
{
|
||||||
|
await CloseRenderProcess(i, log);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal static bool KeepGoing(Guid jobId)
|
||||||
|
{
|
||||||
|
foreach (var i in _baginstances)
|
||||||
|
{
|
||||||
|
if (i.JobId == jobId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task RemoveProcess(int processId, ILogger log)
|
||||||
{
|
{
|
||||||
foreach (var i in _baginstances)
|
foreach (var i in _baginstances)
|
||||||
{
|
{
|
||||||
if (i.ReporterProcessId == processId)
|
if (i.ReporterProcessId == processId)
|
||||||
{
|
{
|
||||||
ForceCloseProcess(i, log);
|
await CloseRenderProcess(i, log);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user