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

web*_*nia 3 .net c# multithreading windows-services

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

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

因此,每个工作请求将完成工作添加过程.

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

我的解决方法:

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

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

任何工作都非常感谢.

And*_*own 7

摘要

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

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

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

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

在线程上运行和取消任务

在我们查看您的确切上下文之前,最好先查看MSDN - 异步编程模式.在线程上运行和取消作业有三种主要的.NET模式,我按优先顺序列出它们使用:

  • TAP:基于任务的异步模式
    • 基于Task,仅在.NET 4之后才可用
    • 从.NET 4开始运行和控制任何基于线程的活动的首选方法
    • 实现EAP要简单得多
  • EAP:基于事件的异步模式
    • 如果您没有.NET 4或更高版本,则唯一的选择.
    • 很难实现,但是一旦你理解了它就可以推出它并且使用起来非常可靠
  • APM:异步编程模型
    • 除非您维护旧代码或使用旧API,否则不再相关.
    • 即使使用.NET 1.1,您也可以实现EAP版本,因此我不会像您所说的那样实现自己的解决方案

架构

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

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

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

工作引擎

方法如下:

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

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

当他们想要取消时,他们使用UID发送请求,并通过在字典中找到它并告诉它取消来取消任务.

取消工作

在您的代码中,您需要定期检查取消令牌以查看是否应该停止运行代码(如果您使用的是TAP模式,请参阅如何中止/取消TPL任务;如果您使用的是EAP,则需要使用Albahari).此时您将退出作业处理,如果设计得好,您的代码应该在需要时处理IDiposable,从内存中删除大字符串等.

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

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

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

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

可靠性

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

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

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

如果您确实想扩展,或者您的客户端在许多计算机上,并且您有一个或多个服务器的作业引擎"场",那么请查看使用消息队列而不是直接使用OnCustomCommand.

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

技术示例是MSMQ(如果您想维护自己的,或者必须保留在自己的防火墙内),或者Windows Azure Service Bus(WASB) - 这是便宜的,并且已经为您完成.在任何一种情况下,您都希望使用模式和企业集成的最佳实践.在WASB的情况下,有许多(MSDN),许多(BrokeredMessaging的MSDN样本等),许多(基于任务的新API)开发人员资源,以及NuGet包供您使用