.Net 2.0 Windows服务进程通信:数据库还是IPC?
我有一个在 .Net 2.0 环境上运行的 Windows 服务(无法升级到 3/3.5)。 该服务使用 System.Timers.Timer 以 X 秒间隔轮询数据库表上的项目。
Timer.Elapsed 事件处理代码包含在一个锁定语句中,以防止在上一个处理尚未完成的情况下运行下一个 Elapsed 事件。 对于每个项目,都会执行进程 A,然后从数据库中删除该项目。 这是当前的“生产”代码。
需要执行第二个进程(进程 B),但仅针对某些项目(我可以使用条件轻松隔离这些项目),并且仅在它们由进程 A 处理后执行。用于运行进程 B 的资源仅接受一个一次连接。 (因此,不能为每个进程 B 的执行使用多个线程)如果我要在 Timer.Elapsed 事件处理代码上与进程 A 一起运行进程 B,这将极大地延迟事件处理程序的执行,并且更有可能发生经过的事件将无法及时完成下一个事件的执行,从而使系统响应速度降低等。
我认为最好让一个新的单线程执行进程 B(或另一个服务,我认为这有点过分了)。 进程 A 将为进程 B 排队项目,因此如果进程 B 比进程 A 花费更长的时间来完成处理项目,则下一次进程 A 运行只会向进程 B 队列添加更多项目。
我知道使用数据库作为 IPC 并不是一个很好的做法,但考虑到我无法使用 WCF IPC(这可能是我的方法)并且我已经在这里使用数据库了......
< strong>如果我继续使用数据库作为我的 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
}
}
I have a Windows Service running on a .Net 2.0 environment (NOT UPGRADABLE TO 3/3.5).
The service uses a System.Timers.Timer on a X second Interval to poll for items on a database table.
The Timer.Elapsed event handling code is wrapped around a lock statement to prevent the next Elapsed event of running if the previous processing has not been finished. For each item, Process A is executed and then the item is deleted from the database. This is the current "production" code.
A second process (Process B) needs to be executed, but only for some of the items (which I can easily isolate using a condition) and only after they have been handled by Process A. The resource used to run Process B only accepts one connection at a time. (so having multiple threads for each Process B execution is not an option) If I were to run Process B on my Timer.Elapsed event handling code along with Process A, this would greatly delay the event handler execution and make it more probable that an Elapsed event will not finish to execute in time for the next event, making the system less responsive, etc.
I think it would be best to have a new single thread execute Process B (or another service, which I think would be overkill). Process A would queue items for Process B, so if Process B takes longer than Process A to finish processing items, the next Process A run would just add more items to the Process B queue.
I'm aware using a database as IPC is not exactly a great practice, but given the fact that I can't use WCF IPC (which would probably have been my approach) AND I'm already using a database here...
Would it be considered a "bad practice" if I keep using the Database as my IPC mechanism and flag the items on the database once Process A finishes so Process B can select and process them (including the delete)? Or should I still try to use some sort of direct IPC between the threads?
It is VERY important that I'm guaranteed that the items in the queue will persist if the system crashes or the services are shut down.
//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
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以禁用/启用计时器,而不是在timer_elapsed 中使用“锁”吗? 在开始时禁用计时器,然后在“最后”启用计时器。 这样您就不必担心事件重叠。
如果这不是一个选项,并且无论处理如何,计时器必须在每个时间间隔触发一次,然后在数据库中标记该项目并使用两个计时器。 一个计时器用于“进程 A”,一个计时器用于“进程 B”。
Instead of using the "lock" in the timer_elapsed, can you just disable/enable the timer? Disable the timer at the start then enable the timer in a 'finally'. Then you don't have to worry about overlapping events.
If that's not an option and the timer must fire every interval, regardless of processing, then flag the item in the DB and use two timers. One timer for 'Process A' and one timer for 'Process B'.
相反,由于您在问题末尾提到的常见要求,使用数据库作为进程间通信渠道是一种很棒的做法:
只需确保标记发生在与进程 A 所进行的任何其他数据更改相同的事务范围内。
您甚至可以考虑将其分成两个服务,并在逻辑进程 A 和 B 之间使用
MessageQueue
。On the contrary, using a database as your inter-process communication channel is a terrific practice due to the common requirement you mention at the end of your question:
Just make sure that the flagging happens within the same transactional scope as any other data changes wrought by process A.
You might even consider breaking this into two services and using a
MessageQueue
between the logical processes A and B.