我对Windows服务有疑问。有时无法在启动命令后显示以下消息以停止服务并使其处于运行状态:
The service cannot accept control messages at this time
简化的服务实现:
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
public class Service : ServiceBase
{
protected object SyncRoot { get; } = new object();
protected override void OnStart(string[] args)
{
lock (SyncRoot)
{
var task = PerformHealthCheck();
while (!task.Wait(10000))
{
RequestAdditionalTime(10000);
}
Task.Factory.StartNew(() =>
{
//Some logic to start worker threads and initialize some startup processes
//All workers threads actually successfully executed.
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
}
protected override void OnStop()
{
//Code is not reachable sometimes
lock (SyncRoot)
{
//Some stop logic
}
}
private static async Task PerformHealthCheck()
{
int status = 0;
do
{
status = CheckStatus();
if (status == 0)
{
await Task.Delay(20000);
}
}
while (status == 0);
}
private static int CheckStatus()
{
//Calculating HealthCheck status
return 0;
}
}
}
创建逻辑:
internal static class Program
{
private static void Main(string[] args)
{
ServiceBase.Run(new Service());
}
}
OnStart方法成功执行到结束,甚至没有命中OnStop方法。我可以在WinDbg中看到以下服务状态:
16 serviceType
4 currentState
5 controlsAccepted
0 win32ExitCode
0 serviceSpecificExitCode
0 checkPoint
0 waitHint
据我所知,显然该服务处于“运行中”状态,并且已收到停止命令,但未执行(我可以从日志中看到它)。我不明白什么可能阻止该服务执行OnStop方法。在Windows事件视图中可以看到“开始”命令,但是没有“停止”命令。
其他信息:
答案 0 :(得分:3)
在您的示例中,PerformHealthCheck()
将不确定地运行。因此,您的OnStart
永远不会完成。不知道那是否仅仅是因为您的简化示例。
但是,您实际上在发生某些事情时记录了什么?与之类似,记录OnStart方法的结束并确认问题发生时OnStart实际上已完成。在代码注释中,您写//Code is not reachabl..
也在其中记录一些内容?还是在锁内?
顺便说一句,锁定启动和停止似乎是同步的一个好主意,但是作为用户,如果我要停止服务,我真的想停止它。不管它仍然处于启动状态。实际上,如果服务没有响应停止命令,我怀疑90%的时间总之,任务管理器都是下一个停止...如果您尝试以这样的方式重写停止逻辑,那就更好了吗?它会始终执行并中断所有可能执行的操作吗?这可能会解决您的问题,并改善imo体验。
编辑,似乎锁定实际上并不会做任何事情(至少,如果仅在这里使用锁定而不是在其他地方锁定某些东西),即使OS仍为StartPending,OS也不会通过OnStop命令。 :
是否有可能在启动完成前花很长时间启动并且在启动之前调用stop时发生?参见以下示例:
class logger
{
static readonly object _logSync = new object();
public void Log(string message)
{
var m = $"{DateTime.Now.ToString("HH:mm:ss")}; {message}{Environment.NewLine}";
lock(_logSync)
{
File.AppendAllText(@"C:\temp\test.txt", m);
}
}
}
class Program
{
static void Main(string[] args)
{
ServiceBase.Run(new TestHangService());
}
}
class TestHangService : ServiceBase
{
private logger _log;
public TestHangService()
{
_log = new logger();
}
protected override void OnStart(string[] args)
{
_log.Log("OnStart");
Thread.Sleep(30 * 1000);
_log.Log("OnStart exit");
}
protected override void OnStop()
{
_log.Log("OnStop");
}
}
然后
C:\WINDOWS\system32>sc create DeleteMe binpath="C:\testprojects\TestService\TestService\bin\Debug\TestService.exe"
[SC] CreateService SUCCESS
C:\WINDOWS\system32>sc start deleteMe
SERVICE_NAME: deleteMe
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
PID : 27376
FLAGS :
C:\WINDOWS\system32>echo "executed directly after starting"
"executed directly after starting"
C:\WINDOWS\system32>sc stop deleteMe
SERVICE_NAME: deleteMe
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
C:\WINDOWS\system32>echo "waiting for 30 sec"
"waiting for 30 sec"
C:\WINDOWS\system32>sc stop deleteMe
[SC] ControlService FAILED 1061:
The service cannot accept control messages at this time.
记录:
18:32:20; OnStart
18:32:50; OnStart退出
请注意不停止
即使经过10分钟,它也似乎无法恢复(令我感到惊讶):
C:\WINDOWS\system32>sc query deleteme
SERVICE_NAME: deleteme
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
C:\WINDOWS\system32>sc stop deleteme
[SC] ControlService FAILED 1061:
The service cannot accept control messages at this time.
答案 1 :(得分:0)
我的问题是,当我想删除旧版本时,无法停止正在运行的Pulse Secure Service。我这样解决了:
转到Windows开始->管理工具->服务
安全查找脉冲。
右键单击->属性->启动类型->选择禁用
重新启动Windows
卸载旧版本的Pulse Secure:
开始-> Windows系统->控制面板->程序->卸载程序->在此处卸载程序
此后,新安装便可以正常工作了。