Windows服务与计划任务


Answers:


51

更新:

我的原始答案将近四年之后,这个答案已经过时了。自TopShelf以来出现,Windows Services的开发就变得容易了。现在,您只需要弄清楚如何支持故障转移...

原始答案:

我真的不是Windows Scheduler的粉丝。用户密码必须作为@moodforall提供上面指出的,当有人更改该用户的密码时,这很有趣。

Windows Scheduler的另一个主要烦人之处是它以交互方式运行,而不是作为后台进程运行。在RDP会话中每20分钟弹出15个MS-DOS窗口时,您会踢自己没有安装为Windows服务的窗口。

无论您选择什么,我当然都建议您将处理代码从控制台应用程序或Windows服务中分离到不同的组件中。然后,您可以选择从控制台应用程序调用工作进程并将其挂接到Windows Scheduler,或者使用Windows服务。

您会发现安排Windows服务并不好玩。一个相当普遍的情况是您有一个长期运行的进程,希望定期运行。但是,如果您正在处理队列,那么您实际上不希望同一工作人员的两个实例处理同一队列。因此,您需要管理计时器,以确保长时间运行的进程是否运行的时间超过了指定的计时器间隔,直到现有进程完成后,它才会再次启动。

在写完所有这些之后,您会认为,为什么我不只是使用Thread.Sleep?这使我可以让当前线程继续运行,直到完成为止,然后暂停间隔开始,线程进入睡眠状态,并在需要的时间后再次启动。整齐!

然后,您会与许多专家一起阅读Internet上的所有建议,告诉您这实际上是一种不良的编程习惯:

http://msmvps.com/blogs/peterritchie/archive/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program.aspx

因此,您会挠头思考,WTF,撤消待处理的结帐->是的,我确定->撤消今天的所有工作.....该死,该死,该死...。

但是,即使每个人都认为这很糟糕,我还是喜欢这种模式:

OnStart方法为单线程方法。

protected override void OnStart (string args) {

   // Create worker thread; this will invoke the WorkerFunction
   // when we start it.
   // Since we use a separate worker thread, the main service
   // thread will return quickly, telling Windows that service has started
   ThreadStart st = new ThreadStart(WorkerFunction);
   workerThread = new Thread(st);

   // set flag to indicate worker thread is active
   serviceStarted = true;

   // start the thread
   workerThread.Start();
}

该代码实例化了一个单独的线程,并将我们的辅助函数附加到该线程。然后,它启动线程并让OnStart事件完成,以使Windows认为该服务未挂起。

单线程方法的辅助方法。

/// <summary>
/// This function will do all the work
/// Once it is done with its tasks, it will be suspended for some time;
/// it will continue to repeat this until the service is stopped
/// </summary>
private void WorkerFunction() {

   // start an endless loop; loop will abort only when "serviceStarted"
   // flag = false
   while (serviceStarted) {

      // do something
      // exception handling omitted here for simplicity
      EventLog.WriteEntry("Service working",
         System.Diagnostics.EventLogEntryType.Information);

      // yield
      if (serviceStarted) {
         Thread.Sleep(new TimeSpan(0, interval, 0));
      }
   }

   // time to end the thread
   Thread.CurrentThread.Abort();
}

OnStop方法为单线程方法。

protected override void OnStop() {

   // flag to tell the worker process to stop
   serviceStarted = false;

   // give it a little time to finish any pending work
   workerThread.Join(new TimeSpan(0,2,0));
}

来源:http : //tutorials.csharp-online.net/Creating_a_.NET_Windows_Service%E2%80%94Alternative_1%3a_Use_a_Separate_Thread (无效链接)

多年来,我一直在运行许多类似的Windows服务,并且对我有用。我仍然没有看到人们同意的推荐模式。做适合您的事情。


2
确实,您可能希望使用自己的服务帐户来运行服务。如果所有内容都运行SERVICE或NETWORKSERVICE,则表示您正在授予您的应用可能不需要的权限(这可能会冒着不仅威胁一台服务器,而且威胁整个网络的风险。)
Matthew Whited

1
确实。我认为我没有另外说明吗?
丽贝卡

4
您在第一段中另有暗示。如果您不使用内置帐户之一,则服务所需的用户密码与任务计划程序的密码相同。
尼克·考克斯

1
@MatthewWhited这NT AUTHORITY\NetworkService是一个具有有限权限的帐户。
伊恩·博伊德

1
@IanBoyd包括分配给与其他应用程序相关的NetworkService的任何权限。
Matthew Whited

16

这里有些错误信息。Windows Scheduler完全能够在后台运行任务,而无需弹出窗口且不需要密码。在NT AUTHORITY \ SYSTEM帐户下运行它。使用此schtasks开关:

/ ru系统

但是可以,对于访问网络资源,最佳实践是具有单独的未过期密码策略的服务帐户。

编辑

根据您的操作系统和任务本身的要求,使用该/ru选项,您可能可以使用特权比本地系统少的帐户。

从精美的手册

/RU username

A value that specifies the user context under which the task runs. 
For the system account, valid values are "", "NT AUTHORITY\SYSTEM", or "SYSTEM". 
For Task Scheduler 2.0 tasks, "NT AUTHORITY\LOCALSERVICE", and 
"NT AUTHORITY\NETWORKSERVICE" are also valid values.

Vista和Server 2008中提供了Task Scheduler 2.0

在XP和Server 2003中,system是唯一的选择。


2
请以Local Service(aka NT AUTHORITY\LocalService)而不是LocalSystem(aka .\LocalSystem)的身份运行。前者具有有限的权利,而后者是管理员
Ian Boyd

1
有额外的账户LocalService,并NetworkService在可schtasksV2 Vista的开始,并应优先在可能的情况。当时,这是指schtasksXP和Server 2003中System的版本,根据旧版本手册technet.microsoft.com/zh-cn/library/bb490996.aspx
Amit Naidu

在XP上,您不能将计划任务作为SYSTEM运行。祝你好运。这是一个很好的总结:cwl.cc/2011/12/run-scheduled-task-as-system.html
Pupsik

11

启动和退出应用程序的开销是多少?每两分钟很经常。与如此频繁地执行您的应用程序相比,服务可能会使系统运行更流畅。

两种解决方案都可以在用户未登录时运行该程序,因此两者没有区别。但是,编写服务比普通的桌面应用程序要复杂得多-您可能需要一个单独的GUI客户端,该客户端将通过TCP / IP,命名管道等与服务应用程序进行通信。

从用户的POV,我想知道哪个更易于控制。对于大多数非技术用户来说,服务和计划任务几乎都是遥不可及的,也就是说,他们甚至都不会意识到它们的存在并且可以配置/停止/重新计划等等。


10

在.NET开发中,我通常从开发控制台应用程序开始,该应用程序将运行并将所有日志记录输出到控制台窗口。但是,当它与command参数一起运行时,这只是一个控制台应用程序/console。如果不使用此参数运行它,它将充当Windows服务,它将继续在我自己的自定义编码计划计时器上运行。

我认为Windows服务通常用于管理其他应用程序,而不是长期运行的应用程序。或..它们正在不断运行重量级应用程序,例如SQL Server,BizTalk,RPC连接,IIS(即使IIS从技术上讲将工作分担到其他进程)。

就个人而言,相对于Window Services,我更喜欢预定的任务来执行重复性维护任务和应用程序,例如文件复制/同步,批量电子邮件发送,文件的删除或归档,数据校正(在其他解决方法不可用时)。

对于一个项目,我参与了8或9 Windows服务的开发,但这些服务位于内存中,处于空闲状态,每个实例占用20MB或更多内存。计划任务将完成其任务,并立即释放内存。


8

“服务”一词与“服务”有共同之处。预计它将始终运行并“服务”。任务就是任务。

角色扮演。如果我是另一个操作系统,应用程序或设备,并且我调用了服务,那么我希望它正在运行,并且希望得到响应。如果我(操作系统,应用程序,开发人员)只需要执行一个隔离的任务,那么我将执行一个任务,但是如果我希望进行通信(可能是双向通信),则需要一个服务。这与最有效的方式有关,以便使两件事进行通信,或者使一件事情要执行单个任务。

然后是调度方面。如果您希望某些内容在特定时间运行,请安排时间表。如果您不知道何时需要它,或者“即时​​”需要它,请服务。

我的反应本质上是更具哲学性的,因为这与人类如何与他人互动和合作非常相似。我们越了解交流的技巧,“实体”越了解它们的作用,这个决定就越容易。

抛开所有哲学,当您像我的IT部门经常做的那样“快速制作原型”时,您将尽一切努力来维持生计。一旦原型设计和概念证明不可行,通常是在早期计划和发现中,您就必须确定对于长期可持续性而言更可靠的方法。

好的,总而言之,它高度依赖于许多因素,但是希望这能提供见解而不是造成混淆。


4

Windows服务不需要任何人登录,Windows具有停止,启动和记录服务结果的功能。

预定任务不需要您学习如何编写Windows服务。


9
调度的任务也可以在不登录用户的情况下运行,但是必须将用户的密码提供给调度代理。
MarekJedliński08年

1
@moodforaday除非帐户没有配置通过(例如NT AUTHORITY\LocalServiceNT AUTHORITY\NetworkService)。因为帐户没有密码,所以提供的任何密码都会被忽略。
伊恩·博伊德

4
  1. 使用正确的权限更容易设置和锁定Windows服务。
  2. 服务更具“可见性”,这意味着每个人(即技术人员)都知道要看哪里。

5
您的第一点也适用于计划任务。我不确定“更明显”是什么意思。可以像查看服务一样轻松地查看计划任务。
w4g3n3r

@ w4g3n3r:大多数技术人员都知道如何查看Windows服务以查看正在运行的内容。此外,如果它是一项服务(并且正在运行),它将显示在常规“任务管理器”列表中。很少有人使用预定任务。
NotMe

此外,技术人员知道在出现问题时会在事件查看器中查看。计划任务将该信息存储在文件系统上的日志文件中。我愿意打赌大多数人甚至都不知道在哪里寻找。
NotMe

1
除非您有统计信息,否则我不会同意“很少有人使用计划任务”。我一直都在看他们。对于需要每2分钟运行一次的非编码器,他们只需导航到“计划任务”(与“服务”相同的难度),但是要创建一个新的向导即可。因此,他们所需要知道的只是程序或脚本的位置以及运行频率。现在,如果您知道如何编码,并且将计算机连接到网络上,则需要保护登录名,需要使用内置处理来防止多个实例(如果一个实例运行2分钟以上),那么我将提供一项服务。
加里

4
“大多数技术人员都知道如何查看Windows服务以查看正在运行的内容”。这是服务的问题之一;它们一直在运行-只是为了保持正在运行的进程的布尔值而消耗大量用户和内核资源。这就是为什么Microsoft将尽可能多的服务合并到单个进程中的原因(svchost.exe);只需通过流程即可消除不必要的资源消耗。
伊恩·博伊德

2

Why not provide both?

In the past I've put the 'core' bits in a library and wrapped a call to Whatever.GoGoGo() in both a service as well as a console app.

对于某些您每两分钟触发一次的事件,它的作用并不大(例如,只是一个“ ping”类型的函数)。包装程序不必只包含一个方法调用和一些日志记录。


2

这是一个古老的问题,但我想分享一下我所面临的。

最近,我被要求捕获雷达的屏幕截图(从气象网站获取)并每10分钟将其保存在服务器中一次。

这需要我使用WebBrowser。我通常会提供Windows服务,因此我决定也提供这一服务,但它会继续崩溃。这是我在事件查看器中看到的 错误”模块路径中:C:\ Windows \ system32 \ MSHTML.dll

Since the task was urgent and I had very less time to research and experiment, I decided to use a simple console application and triggered it as a task and it executed smoothly.

I really liked the article by Jon Galloway recommended in accepted answer by Mark Ransom.

Recently passwords on the servers were changed without acknowledging me and all the services failed to execute since they could not logon. So ppl claiming in the article comments that this is a problem. I think windows services can face same problem (Pls. correct me if I am wrong, I am jus a newbie)

另外提到的事情,如果使用任务计划程序窗口弹出或控制台窗口弹出。我从来没有面对过。它可能会弹出,但至少是瞬时的。


我认为乔恩·加洛韦的文章提出了一些好的观点。另外,对于因密码更改或其他原因导致计划任务无法执行的投诉,可以响应计划任务无法运行的情况,因此您可以通知用户或您想执行的任何操作。在这里看到的解决方案:superuser.com/questions/249103/...
丹Csharpster

1

通常,核心信息是并且应该是代码本身必须对每个“触发器/客户端”都可执行。因此,从一种方法切换到另一种方法不应该是火箭科学。

In the past we used more or less always Windows Services but since also more and more of our customers switch to Azure step by step and the swap from a Console App (deployed as a Scheduled Task) to a WebJob in Azure is much easier than from a Windows Service, we focus on Scheduled Tasks for now. If we run into limitations, we just ramp up the Windows Service project and call the same logic from there (as long as customers are working OnPrem..) :)

BR, y


0

Windows services want more patience until it's done. It has a bit hard debug and install. It's faceless. If you need a task which must be done in every second, minute or hour, you should choice Windows Service.

Scheduled Task is quickly developed and has a face. If you need a daily or weekly task, you can use Scheduled Task.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.