高优先级的自定义命令Windows服务

时间:2013-05-09 15:11:15

标签: c# .net multithreading windows-services

我有一个部署在Windows Server 2008中的Work Tracker WPF应用程序,此Tracker应用程序正在与(Tracker)Windows服务VIA WCF服务进行通信。

用户可以创建任何工作条目/编辑/添加/删除/取消工人跟踪器GUI应用程序中的任何工作条目。在内部,它将向Windows服务发送请求。 Windows服务将获取工作请求并在多线程中处理它。每个workrequest条目实际上将在输出文件夹位置创建n个工作文件(基于工作优先级)。

因此,每个工作请求都将用于完成工作添加过程。

现在我的问题是如果我取消当前正在创建的工作条目。我想在RUNTIME中停止当前的Windows服务工作。为工作创建输出文件的当前线程应该是STOPPED。所有线程都应该被杀死。一旦用户请求取消,就应删除所有线程资源。

我的解决方法:

我使用Windows Service On Custom Command方法在运行时向Windows服务发送自定义值。我在这里实现的是处理当前工作或当前线程(即为收到的工作项创建输出文件)。然后它将转到自定义命令以取消请求。

有没有办法让我们在获得自定义命令后停止工作项请求。

非常感谢任何工作。

1 个答案:

答案 0 :(得分:7)

摘要

您实际上是在为长时间运行的任务运行任务主机,并且能够取消这些任务。您的具体问题似乎想知道在.NET中实现它的最佳方法。你的架构很好,虽然你勇于推出自己的架构而不是使用现有的框架,但你还没有提到过以后扩展你的架构。

我的偏好是使用TPL Task对象。它支持取消,并且易于轮询进度等。您只能在.NET 4中使用它。

如果没有基本上为您设计整个作业托管引擎并且知道您的.NET版本,则很难提供代码。我已经在下面详细描述了这些步骤,并参考了示例代码。

使用Windows服务OnCustomCommand的方法很好,如果您有客户端服务通信选项,也可以使用消息服务(见下文)。这对于您有许多客户端与中央作业服务进行通信,并且作业服务与客户端不在同一台计算机上的情况更为合适。

在线程上运行和取消任务

在我们查看您的确切背景之前,最好先查看MSDN - Asynchronous Programming Patterns。在线程上运行和取消作业有三种主要的.NET模式,我按优先顺序列出它们:

  • TAP:Task-based Asynchronous Pattern
    • 基于Task,仅在.NET 4之后才可用
    • 从.NET 4开始运行和控制任何基于线程的活动的首选方法
    • 实施EAP更简单
  • EAP:Event-based Asynchronous Pattern
    • 如果您没有.NET 4或更高版本,则唯一的选择。
    • 很难实现,但是一旦你理解了它就可以推出它并且使用它是非常可靠的
  • APM:Asynchronous Programming Model
    • 不再相关,除非您维护旧代码或使用旧API。
    • 即使使用.NET 1.1,您也可以实现EAP版本,因此我不会覆盖您所说的实施自己的解决方案

架构

想象一下这就像基于REST的服务。

  • 客户提交作业,并返回作业的标识符
  • 作业引擎然后在准备就绪时接收作业并开始运行
  • 如果客户不再需要这份工作,那么他们会删除该工作,使用它的标识符

这样客户端就完全与作业引擎的工作隔离,并且可以随着时间的推移改进作业引擎。

作业引擎

方法如下:

  • 对于提交的任务,生成通用标识符(UID),以便您可以:
    • 确定正在运行的任务
    • 投票结果
    • 如果需要,取消任务
  • 将该UID返回给客户
  • 使用该标识符对作业进行排队
  • 当你有资源时
    • 通过创建任务
    • 来运行作业
    • 将任务存储在字典中,将UID作为键

当客户端想要结果时,他们使用UID发送请求,并通过检查从字典中检索的任务来返回进度。如果任务完成,他们可以发送完成数据的请求,或者在您的情况下,只需去阅读已完成的文件。

当他们想要取消时,他们会发送带有UID的请求,并通过在字典中找到它并告诉它取消来取消任务。

取消职位

在您的代码中,您需要定期检查取消令牌,看看是否应停止运行代码(如果您使用的是TAP模式,请参阅How do I abort/cancel TPL Tasks?,或Albahari if you are using EAP)。此时您将退出作业处理,如果设计得好,您的代码应该在需要时处理IDiposables,从内存中删除大字符串等。

取消的基本前提是您检查取消令牌:

  • 在需要很长时间的工作块之后(例如,调用外部API)
  • 在您控制的循环(forforeachdowhile)内,检查每次迭代
  • 在一长串顺序代码中,可能需要花费一些时间",您可以插入点来定期检查

您需要定义对取消做出反应的速度 - 对于Windows服务,它应该在几毫秒内,最好是确保窗口在重新启动或停止服务时没有问题。

有些人使用线程完成整个过程,并通过终止线程 - 这很难看,不再推荐了。

<强>可靠性

您需要问:如果您的服务器重新启动,Windows服务崩溃,或者发生任何其他异常导致您丢失不完整的工作,会发生什么?在这种情况下,您可能需要一个可靠的队列体系结构,以便能够重新启动作业,或重建您尚未开始的作业队列。

如果您不想扩展,这很简单 - 使用Windows服务存储作业信息的本地数据库。

  • 提交作业时,将其详细信息记录在数据库中
  • 当您开始工作时,请根据数据库中的工作记录进行记录
  • 当客户端收集作业时,将其标记为数据库中的延迟垃圾收集,然后在设定的时间(1小时,1天......)后将其删除
  • 如果您的服务重新开始,并且有正在进行的工作&#34;然后重新排队,然后再次启动你的工作引擎。

如果你想扩展,或者你的客户在许多计算机上,并且你有一个工作引擎&#34; farm&#34;一个或多个服务器,然后查看使用消息队列而不是使用OnCustomCommand直接通信。

消息队列有多种好处。它们将允许您可靠地将作业提交到中央队列,然后许多工作人员可以接收并处理这些作业,并将您的客户端和服务器分离,以便您可以扩展您的作业运行服务。它们用于确保以高度分离的方式可靠地提交和处理作业,这可以在本地或全局工作,但始终可靠,您甚至可以将其与在云工作者上运行Windows服务相结合,您可以动态扩展。 / p>

技术的例子是MSMQ(如果你想维护自己的,或者必须留在你自己的防火墙内),或Windows Azure Service Bus (WASB) - 这是便宜的,已经为你完成了。在任何一种情况下,您都希望使用Patterns and Best Practices for Enterprise Integration。对于WASB,则有many (MSDN)many (MSDN samples for BrokeredMessaging etc.)many (new Task-based API)开发人员资源和NuGet packages供您使用