Windows 服务中 OnShutdown() 事件的奇怪行为
Weird behavior with OnShutdown() event in a Windows Service
我在vb.net(VS2017,目标.net Framework 4.5)中开发了windows服务。
windows 服务自动执行 sql- 服务器备份(基于计时器),删除旧的备份文件,读写 .ini 文件并在某些情况下发送电子邮件和 - 诅咒 - 写入事件日志.该服务必须在 windows 服务器 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 是 在 运行 时设置为真)。
在 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 ...”不会写入事件日志。
感谢任何提示:-)
首先,感谢@craig 对我的打字错误的评论(在我的第一篇文章中,我使用 my.OnShutdown() 而不是 MyBase.OnShutDown()。我现在已经在我的文章中更正了这个(但这并不能解决我的问题)。也感谢@CoreTech 的评论。
看来,我现在已经找到了 my 需求的解决方法...
我进一步查询了互联网并做了很多“try-and-errors”。
我个人的发现(可能有误):
看起来,在 OnShutDown() 事件中几乎没有任何保证,因为系统(服务器和服务)以不明确定义的顺序.
下降
所以...也许可以写入事件日志中的条目,也许不能。
也许可以写入(自定义).ini 中的条目,也许不能。
通过我的尝试,我从未能够在 OnShutDown() 中使用 SMTP 发送电子邮件(通过 SMTP-server)。
这可以解释我奇怪的(不理解的)问题(“移动目标”)。
我只是想知道,当服务器关闭并发送电子邮件时,通知客户(和我们)(以及何时) 服务器已启动并且 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 ) 中,每次重启都会保留一个标志文件。
任何 文件 ( 3 ) 包含带有 服务器关闭 时间戳的文本(而不是 windows 服务重启)
在“根目录”\prog\ ( 1 )写了一个类似的flag文件,
但没有日期时间戳(仅 ( 4 ))...所以此文件名始终相同。
在服务的 OnStart() 中,我检查了标志文件是否存储在“根目录”\Prog\ ( 1 ) 中。
如果是,将发送一封电子邮件“服务器在 'timestamp in flag file' 关闭,windows 服务已重新启动并再次运行...”。
发送邮件后,“主标志文件”自动删除
注意:因为我们在 ( 2 ) 中也有文件,所以我们可以理解任何重启。
这不是我最初想要的,但它有效(至少对我而言;-)。
也许这对某些人有帮助,但也被一种奇怪的行为“绊倒”了……
我在vb.net(VS2017,目标.net Framework 4.5)中开发了windows服务。
windows 服务自动执行 sql- 服务器备份(基于计时器),删除旧的备份文件,读写 .ini 文件并在某些情况下发送电子邮件和 - 诅咒 - 写入事件日志.该服务必须在 windows 服务器 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 是 在 运行 时设置为真)。
在 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 ...”不会写入事件日志。
感谢任何提示:-)
首先,感谢@craig 对我的打字错误的评论(在我的第一篇文章中,我使用 my.OnShutdown() 而不是 MyBase.OnShutDown()。我现在已经在我的文章中更正了这个(但这并不能解决我的问题)。也感谢@CoreTech 的评论。
看来,我现在已经找到了 my 需求的解决方法...
我进一步查询了互联网并做了很多“try-and-errors”。
我个人的发现(可能有误):
看起来,在 OnShutDown() 事件中几乎没有任何保证,因为系统(服务器和服务)以不明确定义的顺序.
下降
所以...也许可以写入事件日志中的条目,也许不能。
也许可以写入(自定义).ini 中的条目,也许不能。
通过我的尝试,我从未能够在 OnShutDown() 中使用 SMTP 发送电子邮件(通过 SMTP-server)。
这可以解释我奇怪的(不理解的)问题(“移动目标”)。
我只是想知道,当服务器关闭并发送电子邮件时,通知客户(和我们)(以及何时) 服务器已启动并且 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
备注:
在启动时,我得到启动路径(到服务)。 “主标志文件”被写入该目录。 “保存标志文件”写在该目录的子目录中(另请参见下面的屏幕截图)。
为了更好地理解:
任何 文件 ( 3 ) 包含带有 服务器关闭 时间戳的文本(而不是 windows 服务重启)
在“根目录”\prog\ ( 1 )写了一个类似的flag文件,
但没有日期时间戳(仅 ( 4 ))...所以此文件名始终相同。
在服务的 OnStart() 中,我检查了标志文件是否存储在“根目录”\Prog\ ( 1 ) 中。
如果是,将发送一封电子邮件“服务器在 'timestamp in flag file' 关闭,windows 服务已重新启动并再次运行...”。
发送邮件后,“主标志文件”自动删除
注意:因为我们在 ( 2 ) 中也有文件,所以我们可以理解任何重启。
这不是我最初想要的,但它有效(至少对我而言;-)。
也许这对某些人有帮助,但也被一种奇怪的行为“绊倒”了……