如何从单独的C#程序启动事件?
我正在开发的C#程序有两个独立的组件:Task Creator(TC)和Task Processor(TP)。 TC附加到Web服务,该服务不断将新任务插入数据库表。另一方面,TP从同一个表中读取并处理每个任务,然后将状态更新回同一个表。它几乎就像一个队列,但使用数据库完成,而不是像MSMQ。 TP每隔5秒唤醒并从表中读取以检查未处理的任务,但这会对性能产生一些影响。当没有新任务时,从SQL语句的哪个位置启动select会有点浪费。理想的方法是使用某种通知方法,当插入新任务时,TP会收到通知,然后从梦中醒来检查新任务。
当前解决方案:
diagram of current solution http://yuml.me/3b49bcfd
理想解决方案:
答案 0 :(得分:4)
我会推荐MSMQ。 :)我不确定你为什么不使用它,但你确实在你的问题中提到它。这几乎就是MSMQ为应用程序之间的持久事件而设计的。它主要支持发布/订阅消息模型...基于您的“理想解决方案”正是您所需要的:TC是发布者,TP是订阅者。 TC注册任务,然后在其发布队列中删除消息。 TP任务不需要启动并运行,以便TC成功地将消息放入其队列中,但是当TP任务正在运行时,它将接收通知并按照优先顺序处理队列中的消息。
如果MSMQ不是一个选项,您也可以使用WCF。使用WCF而不是pub / sub,您可以选择FAF(fire and forget)消息模型。 TP将发布TC将消费的服务。 TC只需要向TP的服务发送消息,以通知TP新任务。这个模型的缺点是TC依赖于TP,这可能不是想法。 TP也必须运行才能使TC成功运行,因为它依赖于TP的服务。使用MSMQ方法,TP和TC都不相互依赖,它们仅依赖于MSMQ(一种低耦合方法)。
编辑:
如何使用MSMQ从TC激发事件并响应TP中的事件的示例。
// TC message queue manager, sends messages
public class TaskMessageQueueManager
{
public void NotifySubscribersOfNewTasks()
{
var queue = getQueue(".\private$\TaskNotifications");
queue.Send("Tasks waiting.");
}
private MessageQueue getQueue(string name)
{
MessageQueue queue = null;
try
{
if (!MessageQueue.Exists(name))
{
queue = MessageQueue.Create(name);
}
else
{
queue = new MessageQueue(name);
}
}
catch (Exception ex)
{
throw new InvalidOperationException("An error occurred while retrieving the message queue '" + name + "'.", ex);
}
return queue;
}
}
// TP message queue handler, receives messages
public class TaskMessageQueueHandler
{
private Thread m_thread;
private ManualResetEvent m_signal;
public void Start()
{
m_signal = new ManualResetEvent(false);
m_thread = new Thread(MSMQReceiveLoop);
m_thread.Start();
}
public void Stop()
{
m_signal.Set();
}
private void MSMQReceiveLoop()
{
bool running = true;
MessageQueue queue = getQueue(".\private$\TaskNotifications");
while (running)
{
try
{
var message = queue.Receive(); // Blocks here until a message is received by MSMQ
if (message.Body.ToString() == "Tasks waiting.")
{
// TODO: Fire off process, perhaps another thread, to handle waiting tasks
}
if (m_signal.WaitOne(10)) // Non-blocking check for exit signal
{
running = false; // If Stop method has been called, the signal will be set and we can end loop
}
}
catch
{
// handle error
running = false;
}
}
}
}
消息不必是简单的文本。您可以发送对象或对象图,默认情况下它将自动序列化并格式化为XML。我相信你也可以用二进制格式序列化数据,如果你需要的话。无论哪种方式,你都会注意到没有Thread.Sleep调用或轮询任何地方。循环基于ManualResetEvent退出,允许您在没有硬中止的情况下干净地结束线程。
答案 1 :(得分:2)
查看SQL Server 2005 Query Notifications 。我刚刚了解到它似乎是从SQL Server 2008中提取的,所以它可能不是最好的主意。
我认为MSMQ可能是一个更好的方法。结合nServiceBus,您可以获胜。
另一种方法可能是线程同步事件。
在TP中你可以有类似的东西:
EventWaitHandle taskEvent = new EventWaitHandle(true,
EventResetMode.AutoReset,
"newTask",
out wasCreated);
new Thread(WaitForTask).Start();
...
public void WaitForTask() { while (true) { taskEvent.WaitOne(); ProcessTasks();} }
在TC中:
bool eventExist;
while (!eventExist)
{
try
{
taskEvent= EventWaitHandle.OpenExisting("newTask");
eventExist = true;
}
catch (WaitHandleCannotBeOpenedException)
{
eventExist = false;
Thread.Sleep(1000);
}
}
CreateNewTask();
taskEvent.Set();
不是说我看到每五秒一次电话怎么可能是这样的表现。
答案 2 :(得分:2)
当没有新的任务时,从SQL语句的位置启动select会有点浪费。
单个表上的选择,每5秒使用简单的条件并且没有返回的行通常几乎没有任何成本,不用担心。