【发布时间】:2024-08-18 18:00:02
【问题描述】:
Windows 服务与重复运行程序(例如每两分钟)的计划任务的优缺点是什么?
【问题讨论】:
标签: windows-services scheduled-tasks
Windows 服务与重复运行程序(例如每两分钟)的计划任务的优缺点是什么?
【问题讨论】:
标签: windows-services scheduled-tasks
更新:
在我最初的答案之后将近四年,这个答案已经过时了。自从TopShelf 出现以来,Windows 服务的开发变得容易了。现在您只需要弄清楚如何支持故障转移...
原答案:
我真的不是 Windows 调度程序的粉丝。用户的密码必须按照上面提到的@moodforall 提供,当有人更改该用户的密码时,这很有趣。
Windows 调度程序的另一个主要烦恼是它以交互方式运行,而不是作为后台进程。当在 RDP 会话期间每 20 分钟弹出 15 个 MS-DOS 窗口时,您会因为没有将它们安装为 Windows 服务而自责。
无论您选择什么,我都强烈建议您将处理代码与控制台应用程序或 Windows 服务分开到不同的组件中。然后,您可以选择从控制台应用程序调用工作进程并将其挂接到 Windows 调度程序中,或者使用 Windows 服务。
您会发现调度 Windows 服务并不有趣。一个相当常见的情况是您有一个长时间运行的进程,您希望定期运行该进程。但是,如果您正在处理一个队列,那么您真的不希望同一个工作人员的两个实例处理同一个队列。所以你需要管理计时器,以确保如果你的长时间运行的进程运行时间超过了指定的计时器间隔,它不会再次启动,直到现有进程完成。
在你写完所有这些之后,你会想,我为什么不直接使用 Thread.Sleep?这允许我让当前线程继续运行直到它完成,然后暂停间隔开始,线程进入睡眠状态并在所需时间后再次启动。整洁!
然后,您阅读了互联网上的所有建议,许多专家告诉您这是多么糟糕的编程实践:
所以你会摸不着头脑想一想,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)); }
多年来,我一直在运行许多这样的 Windows 服务,它对我很有用。我还没有看到人们同意的推荐模式。做对你有用的事。
【讨论】:
NT AUTHORITY\NetworkService 是一个权限有限的帐户。
这里有一些错误信息。 Windows Scheduler 完全能够在后台运行任务而不会弹出窗口并且不需要密码。在 NT AUTHORITY\SYSTEM 帐户下运行它。使用这个 schtasks 开关:
/ru 系统
但是,是的,对于访问网络资源,最佳做法是使用具有单独的不过期密码策略的服务帐户。
编辑
根据您的操作系统和任务本身的要求,您可以通过 /ru 选项使用特权低于 Localsystem 的帐户。
来自罚款manual,
/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.
Task Scheduler 2.0 可用于 Vista 和 Server 2008。
在 XP 和 Server 2003 中,system 是唯一的选项。
【讨论】:
Local Service(又名NT AUTHORITY\LocalService)而不是LocalSystem(又名.\LocalSystem)运行。前者权限有限,后者是管理员
LocalService 和 NetworkService 的附加帐户在 schtasks v2 Vista 及更高版本中可用,应尽可能首选。当时,这指的是XP和Server 2003中的schtasks,根据旧版本手册technet.microsoft.com/en-us/library/bb490996.aspx,它只接受System作为参数@
在 .NET 开发中,我通常从开发控制台应用程序开始,它将运行所有日志输出到控制台窗口。但是,当它使用命令参数/console 运行时,这只是一个控制台应用程序。当它在没有此参数的情况下运行时,它充当 Windows 服务,它将在我自己的自定义编码计划计时器上继续运行。
在我看来,Windows 服务通常用于管理其他应用程序,而不是长时间运行的应用程序。或者 .. 它们是持续运行的重量级应用程序,例如 SQL Server、BizTalk、RPC 连接、IIS(即使 IIS 在技术上将工作分流到其他进程)。
就个人而言,我更喜欢计划任务而不是 Window 服务,用于重复性维护任务和应用程序,例如文件复制/同步、批量电子邮件发送、文件删除或归档、数据更正(当其他解决方法不可用时)。
对于一个项目,我参与了 8 或 9 个 Windows 服务的开发,但这些服务在内存中闲置,每个实例占用 20MB 或更多内存。计划任务会做自己的事情,并立即释放内存。
【讨论】:
启动和退出应用程序的开销是多少?每两分钟很常见。与如此频繁地执行应用程序相比,服务可能会让系统运行更顺畅。
两种解决方案都可以在用户未登录时运行程序,因此没有区别。不过,编写服务比普通的桌面应用程序更复杂 - 您可能需要一个单独的 GUI 客户端,该客户端将通过 TCP/IP、命名管道等与服务应用程序通信。
从用户的POV,我想知道哪个更容易控制。对于大多数非技术用户来说,服务和计划任务几乎都遥不可及,即他们甚至不会意识到它们的存在并且可以配置/停止/重新安排等等。
【讨论】:
“服务”一词与“服务器”有一些共同点。预计它将始终运行并“服务”。任务就是任务。
角色扮演。如果我是另一个操作系统、应用程序或设备并且我调用服务,我希望它正在运行并且我希望得到响应。如果我(os、app、dev)只需要执行一个孤立的任务,那么我将执行一个任务,但如果我希望进行通信,可能是双向通信,我想要一个服务。这与两件事情的最有效通信方式有关,或者一件事情想要执行一个任务。
然后是调度方面。如果您想在特定时间运行某些东西,请安排。如果您不知道何时需要它,或者“即时”需要它,请提供服务。
我的回答本质上更具哲学性,因为这与人类与他人互动和工作的方式非常相似。我们越了解沟通的艺术,“实体”越了解他们的角色,这个决定就越容易。
抛开所有哲学不谈,当您像我的 IT 部门经常做的那样“快速制作原型”时,为了维持生计,您必须做任何事情。一旦原型设计和概念验证工作结束,通常是在早期规划和发现阶段,您就必须决定什么对长期可持续性更可靠。
好的,总而言之,它高度依赖于很多因素,但希望这提供了洞察力而不是混乱。
【讨论】:
Windows 服务不需要任何人登录,Windows 具有停止、启动和记录服务结果的功能。
计划任务不需要您学习如何编写 Windows 服务。
【讨论】:
NT AUTHORITY\LocalService,或NT AUTHORITY\NetworkService)。由于帐户没有密码,任何提供的密码都会被忽略。
【讨论】:
这是一个老问题,但我想分享一下我遇到的问题。
最近我被要求捕获雷达的屏幕截图(来自气象网站)并每 10 分钟将其保存在服务器中。
这需要我使用 WebBrowser。 我通常制作 Windows 服务,所以我决定也制作这项服务,但它会一直崩溃。 这是我在事件查看器中看到的 错误模块路径:C:\Windows\system32\MSHTML.dll
由于任务很紧迫,我研究和实验的时间很少,所以我决定使用一个简单的控制台应用程序并将其作为任务触发并顺利执行。
我真的很喜欢 Mark Ransom 在接受的答案中推荐的 article by Jon Galloway。
最近更改了服务器上的密码而没有确认我,并且所有服务都无法执行,因为它们无法登录。 因此,人们在文章 cmets 中声称这是一个问题。我认为 Windows 服务可能会面临同样的问题(如果我错了请纠正我,我只是一个新手)
还有提到的事情,如果使用任务计划程序窗口弹出或控制台窗口弹出。 我从来没有遇到过。它可能会弹出,但至少是即时的。
【讨论】:
为什么不两者都提供?
过去,我将“核心”位放入库中,并在服务和控制台应用程序中封装了对 What.GoGoGo() 的调用。
如果你每两分钟发射一次,那么它的作用不大(例如,只是一个“ping”类型的函数)。包装器不应该只包含一个方法调用和一些日志记录。
【讨论】:
一般来说,核心信息是并且应该是代码本身必须可以从每个“触发器/客户端”执行。因此,从一种方法切换到另一种方法不应该是火箭科学。
过去我们或多或少总是使用 Windows 服务,但由于越来越多的客户逐步切换到 Azure,并且从控制台应用程序(部署为计划任务)到 Azure 中的 WebJob 的交换很多比从 Windows 服务更容易,我们现在专注于计划任务。如果遇到限制,我们只需启动 Windows 服务项目并从那里调用相同的逻辑(只要客户在 OnPrem 上工作..):)
BR, 是的
【讨论】:
在完成之前,Windows 服务需要更多耐心。 它的调试和安装有点困难。是面无表情 如果您需要每秒钟、每分钟或每小时必须完成的任务, 您应该选择 Windows 服务。
Scheduled Task 发展很快,有面子。 如果您需要每天或每周的任务,可以使用计划任务。
【讨论】: