在执行任何函数之前,我如何跟踪时间



我有这个服务,它每秒调用Notification((函数。该功能的作用是检查lastupdatedDateTime.UtcNow之间的时间差,并检查Countdiff是否大于1

如果上述条件成立,则它检查AppGuid是否已经在DB中,如果不是,则插入它并调用发送通知的DoAction()函数。到这里为止一切都很好。

AppGuid已经在DB中时,问题就开始了。

我需要的是,如果AppGuid已经在DB中,那么每15分钟发送一次通知,在这里,我很难跟踪上次发送通知的时间,我试图在上次timestamp更新时进行比较,并试图比较差异,但它不断发送通知,导致管道中出现垃圾邮件。

我试着用秒表类来保持延时,但问题是当应用程序开始发送任何内容时,它会等待15分钟。

如何每15分钟只发送一次通知?

public class DataGetService : DelegatingHandler, IHostedService
{
private Timer _timer;
Stopwatch stopwatch = new Stopwatch();
public Task StartAsync(CancellationToken cancellationToken)
{
stopwatch.Start();
_timer = new Timer(Heartbeat, null, 1000, 1000);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
//Timer does not have a stop. 
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Heartbeat(object state)
{
_ = Notifications(TimeSpan.FromMinutes(15));
}
public async Task Notifications(TimeSpan period)
{
// Result array have: LastUpdated, CountDiff, AppGuid, AppName, Timestamp
foreach (var d in result)
{
var x = _DBcontext.TestEvents.FirstOrDefault(o => o.AppGuid == (Guid)d.AppGuid);
if (DateTime.UtcNow - d.LastUpdated <= TimeSpan.FromMinutes(30) && d.CountDiff > 1)
{
if (x == null)
{
DoAction();
_DBcontext.TestEvents.Add(new TestEvents
{
AppGuid = (Guid)d.AppGuid,
AppName = d.AppName,
Timestamp = DateTime.UtcNow
});
}
else
{   //This is useful if app have crashed or was not able to update in db, it will update the current timestamp. 
if (DateTime.UtcNow - x.Timestamp >= TimeSpan.FromMinutes(30))
{
x.Timestamp = DateTime.UtcNow;
}
else
{
if (stopwatch.Elapsed <= period)
return;
DoAction();
x.Timestamp = DateTime.UtcNow;
}
}
}
}
await _DBcontext.SaveChangesAsync();
stopwatch.Restart();
}
}

如果用户多次尝试密码,我会用同样的方法将其锁定15分钟:与其试图使用跟踪记录上次更新时间的日期字段,不如使用一个专用字段来记录下一个事件的发生时间。在您发送第一个通知时,将其设置为未来日期,并且只有在日期过去时才发送新通知(因此您将日期再次设置为未来(

通过使用"上次更新"字段,如果有关记录的其他内容发生更改,则有可能再次收到通知。如果你觉得把日期放在相关的表格中是不相关的,可以考虑有一个只用于通知事件日期的表格;它只需要一个GUID和一个日期,然后它就可以为数据库中任何表中的任何对象ID运行(如果GUID是唯一的(-在这种情况下,"在时间y之前不发送GUID为x的实体的信息"是一件很容易编码的事,事件系统不需要知道它报告的实体的任何信息。如果子系统愿意,可以让它们每秒钟天真地引发一次事件,但通知的发送只能每X分钟发生一次,因此所有临时通知都会被终止。这也简化了发出消息的系统;它可以只是提出它们,而不关心是否应该实际通知的逻辑

对于未来的答案寻求者:

我添加了futureTime变量,它将15分钟添加到DB的时间戳中。

有趣的是,当我与if(DateTime.UtcNow == futureTime)进行比较时,条件从未变为真,原因是我所理解的是,在执行过程中,我每秒都会调用这个函数,不知何故,系统跳过了产生false条件的时间。

为了克服这一点,我采用了差值(DateTime.UtcNow - futureTime),并考虑了秒的容差。

if (DateTime.UtcNow - d.LastUpdated <= TimeSpan.FromMinutes(30) && d.CountDiff > 1)
{
if (x == null)
{
DoAction();
_DBcontext.TestEvents.Add(new TestEvents
{
AppGuid = (Guid)item.AppGuid,
AppName = item.AppName,
Timestamp = DateTime.UtcNow
});
}
//This is useful if app have crashed or was not able to update in db, it will update the current timestamp. 
else if (DateTime.UtcNow - x.Timestamp >= TimeSpan.FromMinutes(30))
{
x.Timestamp = DateTime.UtcNow;
}
else
{
//This will set the notification date in future 
DateTime dbtimestamp = x.Timestamp;
DateTime futureTime = dbtimestamp.AddMinutes(15);
if (((DateTime.UtcNow - futureTime) - TimeSpan.FromSeconds(1)).Duration() < TimeSpan.FromSeconds(1.0))
{
DoAction();
x.Timestamp = DateTime.UtcNow;
}
}
}

最新更新