例如,我的系统必须每 60 秒发送大量 http 请求。这是使用 FCM 云消息传递发送推送通知。这是文档。我不是一个特别有经验的 .NET 开发人员。我想问那些在通过邮件实现后台任务方面有经验的人,如何最好地做到这一点。我试过这样的代码:
public class Example
{
private static Timer aTimer;
public static void Main()
{
// Create a timer and set a two second interval.
aTimer = new System.Timers.Timer();
aTimer.Interval = 2000;
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
// Have the timer fire repeated events (true is the default)
aTimer.AutoReset = true;
// Start the timer
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program at any time... ");
Console.ReadLine();
}
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
这是 Microsoft 官方文档中的一个示例System.Timers。起初我认为它非常适合。由于我对实现有要求,从 Web(MVC 控制器)启动和停止分发,在视图上显示分发是否正在进行,使用 DI。但后来我遇到了一个问题。如果一项任务没有时间完成,而另一项任务开始,则系统崩溃。不只是一个任务落下,而是一般的一切,包括 MVC。
然后我想,也许这就是如何做到的。每分钟都有一个可供推送的用户选择。所有这些都添加到某个队列(可能是 rebbitMQ)。这个队列可以正常工作。我的意思是,它按照自己的节奏工作,或者如果没有推送任务则处于空闲状态。我不会每 10 秒重新推送一次用户,所以这个队列迟早会开始在轻量模式下工作。但有时她必须努力工作。这是我在脑海中看到的模式。我的意思是,最终确定。每隔 60 秒,就会启动一组用户进行推送,将用户添加到某个队列中,当有任务时,队列会按照自己的节奏发送推送。这里出现了问题:
- 可行吗?
- 是否会有一个定期的定时器来将推送任务写入队列?还是将 cron 与控制台应用程序一起使用?
- 或者,也许有某种现成的调度程序用于此类任务,而我将推送任务添加到队列并发送出去的方案是过度工程?
我试过这样的调度程序https://github.com/fluentscheduler/FluentScheduler。他有一个非常奇怪的DI。一切都以某种方式在静态方法上。尝试过 托管服务。但我不明白如何从 Web 停止或启动这样的服务,Start 和 Stop 方法的工作很奇怪。我在这里问了一个关于这个的问题。
总的来说,我请你分享那些做出类似决定的人的经验。非常感谢您!
更新
因此,感谢用户 @tym32167 的评论,我决定简单地等待具有工作的方法在我的计时器的某个迭代中完成。为此,在此方法开始时,我将停止计时器,当它结束时,我将再次启动它。这是代码:
public class Scheduler
{
private const int MSecond = 1000;
private readonly int _seconds = MSecond * 10;
private Timer _aTimer;
public void Start()
{
Console.WriteLine("Sending is started ...");
_aTimer = new Timer();
_aTimer.Interval = _seconds;
_aTimer.Elapsed += OnTimedEvent;
_aTimer.AutoReset = true;
_aTimer.Enabled = true;
}
public bool IsWorking()
{
return _aTimer != null;
}
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
await JustDoIt();
}
private async Task JustDoIt()
{
_aTimer.Stop();
// большая и трудная работа
await Task.Delay(1000 * 12);
Console.WriteLine("Done !!");
_aTimer.Start();
}
public void Stop()
{
_aTimer.Stop();
_aTimer = null;
}
}
这是对真实任务的模拟,因为它只是等待并将“完成”打印到控制台。话虽如此,请注意,我正在尝试模拟方法运行时间超过计时器的情况。示例中的计时器运行 10 秒,方法运行 12 秒。如果同时,并行任务会以执行相同的方法开始,那么它们可能会损坏数据库中的数据,因为在我的真实项目,此方法写入数据库并读取 . 这段代码中实现的内容是这样的。首先,计时器启动,执行带有工作的方法。方法一开始关闭定时器,然后执行代码(读、写数据库),打开定时器,我们继续无限循环工作。这堂课一切都正确吗?
计时器选项可能如下所示
我添加了一些随机性,使某些任务持续时间超过 10 秒,而有些则没有。
此外,作业本身放置在 tfy-finally 中,因为如果当前作业失败,我们不希望中止作业。如果你愿意,可以在那里添加一个捕获。
好吧,我使用了另一个计时器 - System.Threading.Timer,在我看来,使用它更容易,甚至更容易。虽然你的选择也没有,如果你这样做
_aTimer.AutoReset = false;如何检查计时器:
结论
具有异步循环的第二个变体(我更喜欢)
操作原理大致相同,可以检查一模一样
结论
看看时间,看看什么最适合你。