This commit is contained in:
2020-06-26 18:22:11 +00:00
parent 1cf91e99ff
commit 3d4433d578
7 changed files with 130 additions and 12 deletions

View File

@@ -471,6 +471,7 @@ namespace AyaNova.Api.Controllers
//TODO: notify OPSNOTIFY
//TODO: notify this should trigger some kind of notification to the ops people
//and a red light on the dashboard
//TODO: this should reset the validity
var errText = $"Physical file {dbObj.StoredFileName} not found despite attachment record, this file is missing";
log.LogError(errText);

View File

@@ -0,0 +1,109 @@
using System.Threading.Tasks;
using AyaNova.Util;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using AyaNova.Models;
using AyaNova.Biz;
using Microsoft.Extensions.Logging;
using Bogus;
using AyaNova.Api.ControllerHelpers;
using System.Diagnostics;
namespace AyaNova.Biz
{
/// <summary>
/// Handle attachment file related cleanup and checking
/// </summary>
internal class AttachmentBiz : BizObject, IJobObject
{
internal AttachmentBiz(AyContext dbcontext, long currentUserId, AuthorizationRoles userRoles)
{
ct = dbcontext;
UserId = currentUserId;
CurrentUserRoles = userRoles;
BizType = AyaType.FileAttachment;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//JOB / OPERATIONS
//
public async Task HandleJobAsync(OpsJob job)
{
//Hand off the particular job to the corresponding processing code
//NOTE: If this code throws an exception the caller (JobsBiz::ProcessJobsAsync) will automatically set the job to failed and log the exeption so
//basically any error condition during job processing should throw up an exception if it can't be handled
//There might be future other job types so doing it like this for all biz job handlers for now
switch (job.JobType)
{
case JobType.AttachmentMaintenance:
await ProcessAttachmentMaintenanceAsync(job);
break;
default:
throw new System.ArgumentOutOfRangeException($"AttachmentBiz.HandleJobAsync -> Invalid job type{job.JobType.ToString()}");
}
}
/// <summary>
/// Handle the job
/// </summary>
/// <param name="job"></param>
private async Task ProcessAttachmentMaintenanceAsync(OpsJob job)
{
ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("AttachmentMaintenanceJob");
ApiServerState apiServerState = (ApiServerState)ServiceProviderProvider.Provider.GetService(typeof(ApiServerState));
//get the current server state so can set back to it later
ApiServerState.ServerState wasServerState = apiServerState.GetState();
string wasReason = apiServerState.Reason;
try
{
await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Running);
await JobsBiz.LogJobAsync(job.GId, $"Starting...");
apiServerState.SetOpsOnly("Attachment file maintenance");
//JObject jobData = JObject.Parse(job.JobInfo);
// var seedLevel = (Seeder.Level.SeedLevel)jobData["seedLevel"].Value<int>();
// var timeZoneOffset = jobData["timeZoneOffset"].Value<decimal>();
// var seed = new Util.Seeder();
// await seed.SeedDatabaseAsync(seedLevel, job.GId, timeZoneOffset);
await JobsBiz.LogJobAsync(job.GId, "Finished.");
await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Completed);
}
catch (Exception ex)
{
log.LogError(ex, "AttachmentMaintenanceJob error during ops");
await JobsBiz.LogJobAsync(job.GId, $"AttachmentMaintenanceJob error during ops\r\n{ex.Message}");
throw ex;
}
finally
{
log.LogInformation($"AttachmentMaintenanceJob: setting server state back to {wasServerState.ToString()}");
apiServerState.SetState(wasServerState, wasReason);
}
}
//Other job handlers here...
/////////////////////////////////////////////////////////////////////
}//eoc
}//eons

View File

@@ -12,7 +12,8 @@ namespace AyaNova.Biz
CoreJobSweeper = 2,
SeedTestData = 4,
BulkCoreBizObjectOperation = 5,
Backup = 6
Backup = 6,
AttachmentMaintenance=7
}

View File

@@ -284,6 +284,9 @@ namespace AyaNova.Biz
case JobType.SeedTestData:
o = (IJobObject)BizObjectFactory.GetBizObject(AyaType.TrialSeeder, ct);
break;
case JobType.AttachmentMaintenance:
o = (IJobObject)BizObjectFactory.GetBizObject(AyaType.FileAttachment, ct);
break;
case JobType.BulkCoreBizObjectOperation:
//bulk op, hand off to biz object to deal with
//note, convention is that there is an idList in job.jobinfo json if preselected else it's all objects of type

View File

@@ -7,9 +7,11 @@ namespace AyaNova.Models
public class FileAttachment
{
public FileAttachment(){
public FileAttachment()
{
//all start out as synchronized
InSync=true;
Exists = true;
}
public long Id { get; set; }
public uint Concurrency { get; set; }
@@ -30,6 +32,8 @@ namespace AyaNova.Models
public DateTime LastModified { get; set; }
public string Notes { get; set; }
public bool InSync {get;set;}//was on disk last sync check
[Required]
public bool Exists { get; set; }//was on disk last sync check
}
}

View File

@@ -22,7 +22,7 @@ namespace AyaNova.Util
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!!
private const int DESIRED_SCHEMA_LEVEL = 11;
internal const long EXPECTED_COLUMN_COUNT = 326;
internal const long EXPECTED_COLUMN_COUNT = 327;
internal const long EXPECTED_INDEX_COUNT = 134;
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::EmptyBizDataFromDatabaseForSeedingOrImporting WHEN NEW TABLES ADDED!!!!
@@ -268,9 +268,9 @@ namespace AyaNova.Util
//await ExecQueryAsync("CREATE INDEX asearchkey_typeid_idx ON asearchkey (objectid, objecttype );");
//This is what is needed during Searching
//search does a lot of hits on searchkey looking for the wordid and optionally objecttype
//In testing this did not pan out, in fact it was much faster to search both with and without a objecttype specified to simply have an index on wordid
// await ExecQueryAsync("CREATE INDEX asearchkey_wordid_otype_idx ON asearchkey (wordid, objecttype);");
//search does a lot of hits on searchkey looking for the wordid and optionally objecttype
//In testing this did not pan out, in fact it was much faster to search both with and without a objecttype specified to simply have an index on wordid
// await ExecQueryAsync("CREATE INDEX asearchkey_wordid_otype_idx ON asearchkey (wordid, objecttype);");
await ExecQueryAsync("CREATE INDEX asearchkey_wordid_idx ON asearchkey (wordid);");
//Search indexing stored procedure
@@ -391,7 +391,7 @@ $BODY$;
await ExecQueryAsync("CREATE TABLE afileattachment (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, " +
"attachtoobjectid bigint not null, attachtoobjecttype integer not null, " +
"storedfilename text not null, displayfilename text not null, contenttype text, lastmodified timestamp not null, notes text, insync bool)");
"storedfilename text not null, displayfilename text not null, contenttype text, lastmodified timestamp not null, notes text, exists bool not null)");
//index required for ops that need to check if file already in db (delete, count refs etc)
//LOOKAT: isn't this useless without the ID as well or is that not fetched?

View File

@@ -424,13 +424,13 @@ namespace AyaNova.Util
/// <param name="fileAttachmentToBeDeleted"></param>
/// <param name="ct"></param>
/// <returns></returns>
internal static async Task<FileAttachment> DeleteFileAttachmentAsync(FileAttachment fileAttachmentToBeDeleted, AyContext ct)
internal static async Task DeleteFileAttachmentAsync(FileAttachment fileAttachmentToBeDeleted, AyContext ct)
{
//check ref count of file
var count = await ct.FileAttachment.LongCountAsync(z => z.StoredFileName == fileAttachmentToBeDeleted.StoredFileName);
//Store in DB
//Remove from the DB
ct.FileAttachment.Remove(fileAttachmentToBeDeleted);
await ct.SaveChangesAsync();
@@ -448,7 +448,7 @@ namespace AyaNova.Util
}
//Return AyFileInfo object
return fileAttachmentToBeDeleted;
return;
}