【问题标题】:Schedule .exe execution based on SQL table timestamps根据 SQL 表时间戳安排 .exe 执行
【发布时间】:2014-12-24 08:02:35
【问题描述】:

问题

我有一个消息记录的 SQL 表,tbl_message_queue,每个都有一个发布时间戳字段(现在或将来)。新记录不断被插入。

当发布时间戳到期时,符合条件的记录需要由控制台应用程序 .exe 处理。处理完成后,将从tbl_message_queue 中删除相应的记录。

应该减少/消除发布时间戳和执行之间的延迟时间。

选项 #1:频繁轮询

我可以通过Windows Task Scheduler 将我的 .exe 设置为每 10-15 秒运行一次。其中将包括如下 SQL 语句:

SELECT *
FROM tbl_message_queue
WHERE qmsg_ts_release <= GETDATE()

这感觉像是一种低效、蛮力、滞后友好的解决方案。但这是我最熟悉的结构。

选项 #2:重新安排 SQL 代理作业

我从未尝试过这个,但似乎它可以工作。这听起来很老套,所以如果这是一个非常糟糕的主意,请原谅我。

我可以创建一个具有CmdExec Job Step 的 SQL 代理作业,并不断重新安排该作业:

  1. UPDATE qmsg_ts_release
  2. INSERT tbl_message_queue
  3. .exe 完成

MIN(qmsg_ts_release) 运行下一个。

...我知道这听起来真的很难看,但它并没有积极的轮询,并且可能会消除任何延迟。

其他选项

对于此类问题,还有其他选择或更好的解决方案吗?我不熟悉消息队列架构中的最佳实践。

MSMQSQL Server Service Broker 这样的东西会更好地解决这类问题吗?我对其他选项知之甚少,不知道从哪里开始。

【问题讨论】:

  • 为什么不做一个 REST 服务并在插入新记录时调用它。
  • @Steve 听起来像是 OP 的问题是记录插入了未来的日期时间以进行处理,例如它不是在插入时立即执行,而是在日期时间被点击时立即执行
  • 类似于选项 1,但可以根据您的未来计划进行扩展的解决方案。我已经为一个类似的项目实现了 Quartz.Net 来安排和邮件通知。可能它将是一个独立的应用程序,因此您可以在将来实现其他目的。 quartz-scheduler.net
  • 如果是这种情况,那么制作一个 REST api,它将在给定时间运行的 windows 调度程序中添加一个新条目

标签: .net sql-server windows message-queue


【解决方案1】:

您的选项 2 应该可以工作,但您可能会遇到意想不到的问题,因为频繁的重新调度很可能不是 SQL 代理的常用用法,而且您几乎无法控制它。

根据您的基础架构,您可以自己实施类似的方法。我将概述算法。

首先,假设您的带有队列的表已被填充并且没有被外部进程更改。

您的控制台应用程序不会启动和停止,但会一直运行。 它启动后立即运行查询以确定位于队列顶部的消息:

SELECT TOP(1) *
FROM tbl_message_queue
ORDER BY qmsg_ts_release

应用程序检查返回消息的时间戳以查看它是过去还是将来。如果是过去,则应立即处理,消息为“过期”。如果有过期消息,则对其进行处理,将其从队列中删除,然后重复查询并查找队列中可能也过期的下一条消息,依此类推。

一旦处理完所有过期消息,循环就会停止。此时,您将获得消息的时间戳。所以,我们只需要等到未来的那一刻。让线程休眠这段时间。一旦它醒来,您就知道现在是处理消息的正确时刻。然后重复整个过程。

如果计算机上的时钟稳定并且可能的等待时间不太长,则此方法相当有效。所有时钟和计时器都会漂移,等待的时间越长,累积的误差就越多。

接下来要考虑的是将新项目添加到队列中时要做什么。将项目添加到队列的进程/过程需要一种方法来通知处理应用程序它可能需要比预期更早唤醒。但首先,做一个简单的检查。将项目添加到队列时,您可以检查队列中是否已有任何具有较小时间戳的项目。如果已经有这样的项目,您可以简单地将新项目添加到队列中,处理应用程序将照常处理它。如果检查显示新项目的时间戳早于队列中已经存在的所有其他时间戳,则意味着处理应用程序正在休眠,我们必须比预期更早唤醒它。

不幸的是,我不知道从存储过程等向外部应用程序发送信号的好方法。我想知道一个自己。在您的情况下,只要将此类项目添加到队列中,只需重新启动处理应用程序就足够了。随着处理应用程序重新启动,它会重新读取队列并相应地继续等待。

一般来说,将项目添加到队列中的进程/应用程序应该能够将更改通知工作应用程序。

我刚刚发现另一个question 说您可以使用SqlDependency 接收此类通知。

【讨论】:

  • 感谢您的回复。我最终采用了类似的模式。消息处理应用程序是用 node.js 编写的,它有一个 http 端点,我将从存储的 proc 或 SQL 触发器中 curl 以通知准备好的新消息。到目前为止,工作非常顺利。此外,节点应用程序将批量处理“过期”消息,而不是一条一条地处理。似乎是一个不错的方法,并且减少了不必要的闲聊。
  • 另外,我选择 node.js 应用程序偶尔 ping SQL 以获取预定消息(而不是尝试跟踪下一次执行)......当我们需要为某些消息安排消息时在未来的某个时间点,我们确定它不需要准确准时...如果它偏离一两分钟也没关系(无论轮询有多频繁)。另外,我不确定setTimeout() 对于非常长的超时/时间表有多可靠。
  • 是的,这完全取决于您的情况。对于长时间的等待,有必要定期唤醒并调整等待时间,因为时钟会漂移。当可靠性很重要时,我使用了混合方法。应用程序侦听来自服务器的信号,并在收到信号后立即进行处理。它还会不频繁地轮询服务器,以防信号在传输过程中丢失。因此,在大多数情况下,信号会立即得到处理,如果信号丢失,仍然可以保证得到处理,但会有一些延迟。
猜你喜欢
  • 1970-01-01
  • 2020-06-02
  • 1970-01-01
  • 2017-12-06
  • 2012-07-15
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 2014-09-20
相关资源
最近更新 更多