在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
- 如果在5秒内收到来自同一客户端的另一个请求,计时器必须不触发经过的事件。
- 如果在5秒内没有收到来自同一客户端的请求,计时器应该运行并触发事件。
定时器与客户端无关
下面是与此相关的进一步业务场景....我正在开发一个Web API,它将在打开电子设备时被使用。只要电源可用,设备就会一直发送它的ON状态。一旦用户关闭该开关,对服务器的请求就停止。
无论设备是ON还是OFF,这些状态都会更新到数据库中。现在更棘手的部分是确定设备何时关闭(很复杂,因为如果设备停止发送任何请求,服务器什么都不知道)。所以每个设备都有一个单独的计时器
首先,感谢@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()
。