From 9720dc94648054d05d5970943f7e996d12aa121c Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Thu, 16 Jul 2020 00:04:04 +0000 Subject: [PATCH] --- server/AyaNova/biz/JobsBiz.cs | 8 +- server/AyaNova/generator/CoreJobNotify.cs | 82 +++++++++++++++++++ .../generator/CoreNotificationSweeper.cs | 78 ------------------ server/AyaNova/models/NotifyEvent.cs | 3 +- server/AyaNova/util/AySchema.cs | 2 +- 5 files changed, 91 insertions(+), 82 deletions(-) create mode 100644 server/AyaNova/generator/CoreJobNotify.cs diff --git a/server/AyaNova/biz/JobsBiz.cs b/server/AyaNova/biz/JobsBiz.cs index 93b1d55f..cf5e7323 100644 --- a/server/AyaNova/biz/JobsBiz.cs +++ b/server/AyaNova/biz/JobsBiz.cs @@ -190,11 +190,15 @@ namespace AyaNova.Biz log.LogCritical(msg); return; } - //TODO: NOTIFICATIONS - //await CoreJobNotify.DoWorkAsync(); + //BACKUP await CoreJobBackup.DoWorkAsync(); + + //NOTIFICATIONS + await CoreJobNotify.DoWorkAsync(); + await CoreNotificationSweeper.DoWorkAsync(); + //JOB SWEEPER await CoreJobSweeper.DoWorkAsync(); diff --git a/server/AyaNova/generator/CoreJobNotify.cs b/server/AyaNova/generator/CoreJobNotify.cs new file mode 100644 index 00000000..fda90e7d --- /dev/null +++ b/server/AyaNova/generator/CoreJobNotify.cs @@ -0,0 +1,82 @@ +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using AyaNova.Models; + +namespace AyaNova.Biz +{ + + /// + /// Notification processor + /// + /// + internal static class CoreJobNotify + { + private static bool NotifyIsRunning = false; + private static ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("CoreJobNotify"); + private static DateTime lastRun = DateTime.MinValue; + private static TimeSpan DELETE_AFTER_AGE = new TimeSpan(90, 0, 0, 0); + private static TimeSpan RUN_EVERY_INTERVAL = new TimeSpan(0, 2, 0);//once every 2 minutes minimum + + //////////////////////////////////////////////////////////////////////////////////////////////// + // DoSweep + // + public static async Task DoWorkAsync() + { + log.LogTrace("Checking if Notify should run"); + if (NotifyIsRunning) + { + log.LogTrace("Notify is running already exiting this cycle"); + return; + } + //This will get triggered roughly every minute, but we don't want to deliver that frequently + if (DateTime.UtcNow - lastRun < RUN_EVERY_INTERVAL) + { + log.LogTrace($"Notify ran less than {RUN_EVERY_INTERVAL}, exiting this cycle"); + return; + } + try + { + NotifyIsRunning = true; + log.LogTrace("Notify set to RUNNING state and starting now"); + + + using (AyContext ct = AyaNova.Util.ServiceProviderProvider.DBContext) + { + //select all jobs with no deliver date or deliver date no longer in future + //Open question: what to do with failed deliveries? + //we dont' want them piling up but we don't want to just dump them do we? + //it should be only mail ones that fail, not app ones, there's no way for an app delivery to fail as it's just put in a table + //### PLAN if it's an smtp delivery that fails and it's to someone who can be delivered in app then it should send an inapp notification of + //delivery failure and still delete the smtp delivery + //If it's not possible to notify the person via in app of the failed smtp then perhaps it notifies OPS personnel and biz admin personnel + //NEW NOTIFICATION SUBSCRIPTION EVENT TYPE: + //OPERATIONS_PROBLEMS - backup, notifications, out of memory, what have you, anyone can subscribe to it regardless of rights + //this is just to let people know there is a problem + + + } + } + catch (Exception ex) + { + + } + finally + { + log.LogTrace("Notify is done setting to not running state and tagging lastRun timestamp"); + lastRun = DateTime.UtcNow; + NotifyIsRunning = false; + } + + } + + + + ///////////////////////////////////////////////////////////////////// + + }//eoc + + +}//eons + diff --git a/server/AyaNova/generator/CoreNotificationSweeper.cs b/server/AyaNova/generator/CoreNotificationSweeper.cs index ef118475..d3e08602 100644 --- a/server/AyaNova/generator/CoreNotificationSweeper.cs +++ b/server/AyaNova/generator/CoreNotificationSweeper.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -8,7 +7,6 @@ using AyaNova.Models; namespace AyaNova.Biz { - /// /// Clean up notification system, keep items down to 90 days /// @@ -52,82 +50,6 @@ namespace AyaNova.Biz } - private static async Task sweepAsync(AyContext ct, DateTime dtDeleteCutoff, JobStatus jobStatus) - { - //Get the deleteable succeeded jobs list - var jobs = await ct.OpsJob - .AsNoTracking() - .Where(z => z.Created < dtDeleteCutoff && z.JobStatus == jobStatus) - .OrderBy(z => z.Created) - .ToListAsync(); - - log.LogTrace($"SweepAsync processing: cutoff={dtDeleteCutoff.ToString()}, for {jobs.Count.ToString()} jobs of status {jobStatus.ToString()}"); - - foreach (OpsJob j in jobs) - { - try - { - - await JobsBiz.RemoveJobAndLogsAsync(j.GId); - } - catch (Exception ex) - { - log.LogError(ex, "sweepAsync exception calling JobsBiz.RemoveJobAndLogsAsync"); - //for now just throw it but this needs to be removed when logging added and better handling - throw (ex); - } - } - } - - - /// - /// Kill jobs that have been stuck in "running" state for too long - /// - private static async Task killStuckJobsAsync(AyContext ct, DateTime dtRunningDeadline) - { - //Get the deleteable succeeded jobs list - var jobs = await ct.OpsJob - .AsNoTracking() - .Where(z => z.Created < dtRunningDeadline && z.JobStatus == JobStatus.Running) - .OrderBy(z => z.Created) - .ToListAsync(); - - log.LogTrace($"killStuckJobsAsync processing: cutoff={dtRunningDeadline.ToString()}, for {jobs.Count.ToString()} jobs of status {JobStatus.Running.ToString()}"); - - foreach (OpsJob j in jobs) - { - //OPSMETRIC - await JobsBiz.LogJobAsync(j.GId, "Job took too long to run - setting to failed"); - log.LogError($"Job found job stuck in running status and set to failed: deadline={dtRunningDeadline.ToString()}, jobId={j.GId.ToString()}, jobname={j.Name}, jobtype={j.JobType.ToString()}, jobObjectType={j.ObjectType.ToString()}, jobObjectId={j.ObjectId.ToString()}"); - await JobsBiz.UpdateJobStatusAsync(j.GId, JobStatus.Failed); - } - } - - - private static async Task SweepInternalJobsLogsAsync(AyContext ct, DateTime dtDeleteCutoff) - { - //Get the deleteable list (this is for reporting, could easily just do it in one go) - var logs = await ct.OpsJobLog - .AsNoTracking() - .Where(z => z.Created < dtDeleteCutoff) - .OrderBy(z => z.Created) - .ToListAsync(); - - log.LogTrace($"SweepInternalJobsLogsAsync processing: cutoff={dtDeleteCutoff.ToString()}, for {logs.Count.ToString()} log entries"); - - foreach (OpsJobLog l in logs) - { - try - { - await ct.Database.ExecuteSqlInterpolatedAsync($"delete from aopsjoblog where gid = {l.GId}"); - } - catch (Exception ex) - { - log.LogError(ex, "SweepInternalJobsLogsAsync exception removed old log entries"); - throw (ex); - } - } - } ///////////////////////////////////////////////////////////////////// diff --git a/server/AyaNova/models/NotifyEvent.cs b/server/AyaNova/models/NotifyEvent.cs index 2e48a984..413bf3d6 100644 --- a/server/AyaNova/models/NotifyEvent.cs +++ b/server/AyaNova/models/NotifyEvent.cs @@ -24,7 +24,8 @@ namespace AyaNova.Models public long SubscriptionId { get; set; } public long? IdValue { get; set; } public decimal? DecValue { get; set; } - public DateTime? EventDate { get; set; } + public DateTime? EventDate { get; set; }//date of the event actually occuring, e.g. WarrantyExpiry date. Duped with delivery date as source of truth in case edit to advance setting in subscription changes delivery date + public DateTime? DeliverDate { get; set; }//date user wants the event notification delivered, usually same as event date but could be set earlier if Advance setting in effect. This is the date consulted for delivery only. public string Message { get; set; } diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index 63aeb3c8..7b3d7e40 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -688,7 +688,7 @@ $BODY$; "idvalue bigint, decvalue decimal(19,4), agevalue interval, deliverymethod integer not null, deliveryaddress text, attachreportid bigint, intags varchar(255) ARRAY, outtags varchar(255) ARRAY)"); await ExecQueryAsync("CREATE TABLE anotifyevent (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, created timestamp not null, " + - "ayatype integer, objectid bigint, eventtype integer not null, subscriptionid bigint not null, idvalue bigint, decvalue decimal(19,4), eventdate timestamp, message text)"); + "ayatype integer, objectid bigint, eventtype integer not null, subscriptionid bigint not null, idvalue bigint, decvalue decimal(19,4), eventdate timestamp, deliverdate timestamp, message text)"); await ExecQueryAsync("CREATE TABLE anotification (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, userid bigint not null, created timestamp not null, ayatype integer, objectid bigint, eventtype integer not null, " + "subscriptionid bigint not null, message text, fetched bool not null)");