我在.Net 2.0环境中运行Windows服务(不能升级到3 / 3.5)。 该服务在X秒Interval上使用System.Timers.Timer来轮询数据库表上的项目。
Timer.Elapsed事件处理代码包含在lock语句中,以防止在前一个处理尚未完成时运行下一个Elapsed事件。对于每个项目,执行进程A,然后从数据库中删除该项目。这是当前的“生产”代码。
需要执行第二个流程(流程B),但仅针对某些项目(我可以使用条件轻松隔离)并且仅在它们由流程A处理之后。用于运行流程B的资源一次只接受一个连接。 (因此,每个进程B执行多个线程不是一个选项)如果我在我的Timer.Elapsed事件处理代码和进程A上运行进程B,这将极大地延迟事件处理程序的执行并使其更有可能经过的事件将无法在下次事件中及时执行,从而降低系统响应速度等。
我认为最好让一个新的单个线程执行进程B(或其他服务,我认为这样做会有点过分)。进程A将为进程B排队项目,因此如果进程B花费的时间比进程A完成处理项目,则下一个进程A运行只会向进程B队列添加更多项目。
我知道使用数据库,因为IPC并不是一个很好的做法,但考虑到我不能使用WCF IPC(这可能是我的方法)而且我已经在这里使用数据库了。 ..
如果我继续使用数据库作为我的IPC机制并在进程A完成后标记数据库上的项目,那么它会被视为“不良做法”,因此进程B可以选择并处理它们(包括删除)?或者我是否仍应尝试在线程之间使用某种直接IPC?
非常重要的是,我保证如果系统崩溃或服务关闭,队列中的项目将会持续存在。
//This is how my Elapsed event handler should look
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock(this)
{
//Load items from DB
//foreach item
//Run Process A
//if(item.Member == condition)
// Queue item for Process B (DB = reflag, IPC = send message)
//If using IPC delete the item from the DB
}
}
答案 0 :(得分:3)
您可以只禁用/启用计时器,而不是使用timer_elapsed中的“lock”吗?在开始时禁用定时器,然后在'finally'中启用定时器。然后你不必担心重叠事件。
如果这不是一个选项,并且计时器必须触发每个间隔,无论处理如何,然后标记数据库中的项目并使用两个计时器。 “进程A”的一个计时器和“进程B”的一个计时器。
答案 1 :(得分:2)
相反,由于您在问题的最后提到的共同要求,使用数据库作为进程间通信渠道是一种极好的做法:
我很重要 保证队列中的项目 如果系统崩溃或将继续存在 服务被关闭。
只需确保标记在与进程A所做的任何其他数据更改相同的事务范围内发生。
您甚至可以考虑将此分解为两个服务,并在逻辑进程A和B之间使用MessageQueue
。