在x秒后触发一个事件,但也在它执行之前取消它

本文关键字:执行 取消 事件 一个 | 更新日期: 2023-09-27 17:53:05

我正在开发一个Web API(它工作得很好)。缺失的是什么?以下是Get Action的示例代码:

public IEnumerable<xxxx> Get()
{           
    IEnumerable<xxxx> yyyy = new List<xxxx>();
    //get yyyy from database
    timer = new Timer();
    timer.AutoReset = true;
    timer.Enabled = true;
    timer.Interval = 5000; //miliseconds
    timer.Elapsed += timer_Elapsed;
    timer.Start();
    return yyyy;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    //code to be executed when timer elapses...
}

因此,一旦接收到请求,计时器将被初始化,并以5秒的间隔触发Elapsed事件。下一个后续请求继续....

期望的行为是这样的:

  1. 初始化请求-1
  2. 初始化定时器-1
  3. 如果在5秒内收到来自同一客户端的另一个请求,计时器必须不触发经过的事件。
  4. 如果在5秒内没有收到来自同一客户端的请求,计时器应该运行并触发事件。

定时器与客户端无关

下面是与此相关的进一步业务场景....我正在开发一个Web API,它将在打开电子设备时被使用。只要电源可用,设备就会一直发送它的ON状态。一旦用户关闭该开关,对服务器的请求就停止。

无论设备是ON还是OFF,这些状态都会更新到数据库中。现在更棘手的部分是确定设备何时关闭(很复杂,因为如果设备停止发送任何请求,服务器什么都不知道)。所以每个设备都有一个单独的计时器

在x秒后触发一个事件,但也在它执行之前取消它

首先,感谢@Patrick Hofman对我的指导和思维的突破…我实现了一个类里面有静态属性。

public class DeviceContainer
{
    public static List<DevTimer> timers=new List<DevTimer>();
}
public class DevTimer:Timer
{
    public string Identifier {get; set;}
    public bool IsInUse{get; set;}
}

,然后在上面的代码(问题),我做了以下更改:

public IEnumerable<xxxx> Get(string Id)
{        
    //Check if timer exists in
    if(!DeviceContainer.timers.Any(s=>s.Identifier.Equals(Id)))
    {
         //Create new object of timer, assign identifier =Id, 
         //set interval and initialize it. add it to collection as
         var timer = new DevTimer();
         timer.AutoReset = true;
         timer.Enabled = true;
         timer.Interval = 5000; //miliseconds
         timer.Elapsed += timer_Elapsed;
         timer.IsInUse=true;
         timer.Identifier=Id;             
         DeviceContainer.timers.Add(timer);
         timer.Start();
    }
    else
    {
         //Code to stop the existing timer and start it again.
         var _timer=DeviceContainer.timers.FirstOrDefault(s=>s.Identifier.Equals(Id)) 
                      as DevTimer;
         _timer.Stop();
         _timer.Start();
    }        
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    //code that will turn off the device in DB
}

我不发布整个代码,因为这不是这里的目的。

我会使用微软的响应式框架。

代码如下:

IEnumerable<xxxx> yyyy = new List<xxxx>();
Subject<Unit> clientRequestArrived = new Subject<Unit>();
IDisposable subscription =
    clientRequestArrived
        .Select(_ => Observable.Interval(TimeSpan.FromSeconds(5.0)))
        .Switch()
        .Subscribe(_ =>
        {
            //code to be executed when timer elapses...
            //directly access `yyyy` here
        });

所有你需要做的是调用clientRequestArrived.OnNext(Unit.Default);每次用户请求进来,这将足以让这段代码重置定时器。

如果您想完全停止定时器,只需调用subscription.Dispose()