【问题标题】:Weird behavior with OnShutdown() event in a Windows ServiceWindows 服务中 OnShutdown() 事件的奇怪行为
【发布时间】:2022-02-18 02:39:57
【问题描述】:

我在vb.net(VS2017,目标.net framework 4.5)中开发了一个windows服务
Windows 服务会自动执行 sql-server 备份(基于计时器)、删除旧备份文件、读取和写入 .ini 文件并在某些情况下发送电子邮件以及 - 诅咒 - 写入事件日志。该服务必须在 windows server 2019(标准)上运行。
一切都按预期工作 - 除了 OnShutdown() 事件的处理,这让我抓狂,因为它是一个“移动目标”
如果服务器关闭(正常情况应该是“重启”),我想:

  • 登录事件日志
  • 写入 .ini
  • 发送电子邮件

我的代码 zu OnShutdown():

Protected Overrides Sub OnShutdown()
  cModul = "OnShutdown()"
  ProtokollSchreiben("Der Server wird heruntergefahren...", Typ_Warning)
 '
  DebugProtokollSchreiben("Timer stoppen und anhalten...", Typ_Warning)
  MyTimer.Stop()
  MyTimer.Enabled = False
  DebugProtokollSchreiben("Timer gestoppt und angehalten...", Typ_Warning)
  DebugProtokollSchreiben("Der Server wird heruntergefahren...", Typ_Warning)
  DebugProtokollSchreiben("Vor schreiben .ini...", Typ_Warning)
  cIniFile.WriteInteger("WindowsService", "ServerWurdeGebooted", 1)
  DebugProtokollSchreiben("Nach schreiben .ini...", Typ_Warning)
  DebugProtokollSchreiben("Vor MailversandServerReboot...", Typ_Warning)
  MailversandServerReboot()
 cModul = "OnShutdown()"
  DebugProtokollSchreiben("Nach MailversandServerReboot...", Typ_Warning)
 '
   MyBase.OnShutdown()' call “original event”
End Sub

注意事项:
我设置:

Me.CanShutdown = True

在设计器代码中并在事件日志中写入启动时的实际值(CanShutdown is 在运行时设置为 true)。
在 ProtokollSchreiben() 和 DebugProtokollSchreiben() 中只写入日志条目。 在 MailversandServerReboot() 中,一封电子邮件通过 SMTP 发送(这在服务的其他部分也可以正常工作)。

行为:

  • 有时调用事件(OnShutdown(),有时不调用
  • 如果调用它,大多数情况下,事件日志中的最后一个事件是“Vor schreiben .ini...”(= 在写入 .ini 文件之前)
  • -> 在这种情况下,有时会更新 .ini(尽管下一个日志条目“Nach schreiben .ini...”不会写入事件日志),有时不会

我已经搜索了互联网并阅读了这个 SO-Links:
detect shutdown in window service
Windows Service does seem to do nothing OnShutdown()
Can a Windows Service take hours to shutdown gracefully?

据我所见,我应该有大约 20 秒的时间在 OnShutDown() 中做某事。
要编写事件日志和 .ini 不应该花费一秒钟... .
也许,发送电子邮件(在函数“MailversandServerReboot()”中)可能需要更长的时间,或者当触发 OnShutdown() 时,可能无法发送电子邮件,因为其他(需要的)服务已关闭...
但是,我不明白,有时会调用该事件,有时不会调用该事件,如果它被调用,那么大多数条目“Nach schreiben .ini ...”不会写入事件日志。
感谢您的任何提示:-)

【问题讨论】:

  • 您是否尝试过实现preshutdown notifications
  • 最后一行,如所写,创建了一个无限递归,该递归将以堆栈溢出结束,这可能不是您想要的。它应该是MyBase.OnShutdown()
  • 克雷格:谢谢你说得对(那是一个错字),但也有这个错字,应该写事件日志和.ini,不是这样的。 CoreTech:也谢谢你,不——还没有尝试过。如果我找不到其他解决方案,我会尝试。我发现了更多信息,不能保证 eventnlog 的条目可以写在 OnShutdown 中。我正在尝试实现另一个“解决方案”(直接写一个标志文件)。我会尽快发布我的发现。再次感谢你们。

标签: vb.net windows-services windows-server-2019


【解决方案1】:

首先,感谢@craig 对我的错字的评论(在我的第一个帖子中,我使用 my.OnShutdown() 而不是 MyBase.OnShutDown()。我现在已经在我的帖子中更正了这个问题(但这不能解决我的问题)。也感谢@CoreTech 的评论。
看来,我现在已经找到了满足我的需求的解决方法...
我进一步查询了互联网并做了很多“尝试和错误”。
我的个人发现(可能是错误的):
看起来,在 OnShutDown() 事件中几乎没有任何保证,因为系统(服务器和服务)以不明确的定义顺序关闭
所以......也许可以写入事件日志中的条目,也许不能。 也许可以编写(自定义).ini 中的条目,也许不能。
通过我的尝试,我永远无法在 OnShutDown() 中使用 SMTP 发送电子邮件(通过 SMTP 服务器)。
这可以解释我的奇怪(不理解)问题(“移动目标”)。
我只是想知道,当服务器关闭并发送电子邮件时,通知客户(和我们)(以及何时)服务器已启动并且 Windows 服务再次启动并运行.
仅此,如果服务器确实已启动(不是每次启动服务:-)。
所以..我现在做什么(似乎工作->测试过20 次):

Protected Overrides Sub OnShutdown()
  cModul = "OnShutdown()"
' Write a Flag-File to the Server reboot including a timestamp
  Dim cZeitpunkt As String = System.DateTime.Now.ToShortDateString.ToString.ToString
  cZeitpunkt = cZeitpunkt + ", " + System.DateTime.Now.ToShortTimeString.ToString
  System.IO.File.WriteAllText(cFlagFileNameMitPfad, "Der Windows-Server zum SQL-Server 2019 (WPE) wurde heruntergefahren am: " + cZeitpunkt)
'
' Create an additional file in a sub directory to see, THAT the server was rebooted (also after the service was restarted an had deleted the file in the OnStart() event)
'
' Check if subdirectory exists -> if not -> create it
  If Not System.IO.Directory.Exists(cSaveFlagVerzeichnis) Then
    System.IO.Directory.CreateDirectory(cSaveFlagVerzeichnis)
  End If

‘ Generate DateTimeStamp for Filename (own function)
  Dim cFileTimeStamp As String = DateTime2StringFileName(System.DateTime.Now)
' Do some minor changes to the needed format (cut leading “_” and add it an the end)
  cFileTimeStamp = cFileTimeStamp.Substring(1, cFileTimeStamp.Length - 1) + "_"
  Dim cFlagFileNameSave As String = cSaveFlagVerzeichnis + "\" + cFileTimeStamp + cFlagFileName
' Write the additional file
 System.IO.File.WriteAllText(cFlagFileNameSave, "Der Windows-Server zum SQL-Server 2019 (WPE) wurde heruntergefahren am: " + cZeitpunkt)
'
' Write to the event log (note: it is not guaranteed, that the entries are written, but it’s only informative)
  ProtokollSchreiben("Der Server wird heruntergefahren, Flag-File wurde geschrieben..", Typ_Warning)
  DebugProtokollSchreiben("Der Server wird heruntergefahren, Flag-File wurde geschrieben..", Typ_Warning)
'
  MyBase.OnShutdown() ' Call original event
End Sub

注意事项:
在启动时,我得到启动路径(到服务)。 “主标志文件”被写入该目录。 “保存标志文件”写在该目录的子目录中(另见下面的屏幕截图)。

为了更好地理解: “根目录”是 \prog\ ( 1 )。 在子目录 \SaveRebootFlags\ ( 2 ) 中,每次重启都会保存一个标志文件。
任何 file (3) 都包含带有时间戳的文本,到 服务器关闭(不是 Windows 服务的重新启动) 在“根目录”\prog\ ( 1 ) 中写入了一个类似的标志文件,
但没有日期时间戳(only (4))...所以这个文件名总是一样的。
在服务的 OnStart() 中,我检查标志文件是否存储在“根目录”\Prog\ ( 1 ) 中。
如果是,则会发送一封电子邮件“服务器在'标志文件中的时间戳'时关闭,Windows 服务已重新启动并再次工作......”。
发送邮件后,“主标志文件”被自动删除。
注意:由于我们在 ( 2 ) 中也有文件,因此我们可以理解任何重新启动。
这不是我最初想要的,但它可以工作(至少对我来说;-) .
也许这对某人有帮助,也因为奇怪的行为而被“绊倒”...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    • 2021-10-01
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多