簡體   English   中英

Windows 服務作為本地系統帳戶停留在“啟動”狀態

[英]Windows Service stuck on "starting" status as local system account

我通過 C# 中的控制台應用程序開發了一個 http 服務器,並決定將其轉換為 Windows 服務,以便無需登錄機器即可對其進行初始化。

我按照如何創建 Windows 服務中的所有步驟並選擇帳戶作為“本地系統”,但是當我在我的服務器機器上安裝並按下開始按鈕時,它需要一段時間並給出以下錯誤:

錯誤 1053:服務沒有及時響應啟動或控制請求。

之后,服務狀態停留在“正在啟動”,應用程序無法運行,我什至無法停止服務。

試圖解決此問題,我將其更改為“網絡服務”,因此它可以正常啟動,但是當我使用命令“netstat -an”檢查提示符時,應用程序沒有偵聽我設置的端口。 但是,如果我將其作為控制台應用程序運行,該應用程序會正常偵聽。

因此,我正在尋找以下兩個問題之一的答案:

  1. 我應該怎么做才能使用本地系統帳戶正確啟動服務?
  2. 如果我決定使用網絡服務帳戶,我應該注意什么來保證我的服務作為服務器正常工作?

當我將控制台應用程序轉換為 Windows 服務時,我只是將代碼直接放在 OnStart 方法中。 但是,我意識到 OnStart 方法應該啟動服務,但需要結束一段時間才能真正啟動服務。 所以我創建了一個線程來運行我的服務並讓 OnStart 方法完成。 我測試過,服務運行得很好。 代碼如下:

protected override void OnStart(string[] args)
{
    Listener(); // this method never returns
}

這是它的工作原理:

protected override void OnStart(string[] args)
{
    Thread t = new Thread(new ThreadStart(Listener));
    t.Start();
}

但是我仍然不明白為什么我使用網絡服務帳戶時服務運行(通過了“啟動”狀態,但沒有工作)。 如果有人知道,我會很高興知道原因。

如果您的某個服務沒有響應或在您無法停止的 Windows 服務中顯示掛起,請使用以下說明強制停止該服務。

  • Start -> RunStart -> 鍵入services.msc並按Enter
  • 查找服務並檢查屬性並確定其服務名稱
  • 找到后,打開命令提示符。 鍵入sc queryex [servicename]
  • 識別PID(進程ID)
  • 在同一個命令提示符下輸入taskkill /pid [pid number] /f

檢查 Windows 應用程序事件日志,它可能包含來自服務自動生成的事件源的一些條目(應該與服務具有相同的名稱)。

您可以嘗試使用注冊表中的一個鍵來增加 Windows 服務超時

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

"ServicesPipeTimeout"=dword:300000(300 秒或 5 分鍾)

如果它不存在,則必須創建它。

對我來說,這是一個查看外部隊列的 while 循環。 while 循環繼續運行,直到隊列為空。 僅在Environment.UserInteractive時直接調用計時器事件解決了它。 因此,該服務可以輕松調試,但是當作為服務運行時,它將等待計時器ElapsedEventHandler事件。

服務:

partial class IntegrationService : ServiceBase
{
    private static Logger logger = LogManager.GetCurrentClassLogger();
    private System.Timers.Timer timer;

    public IntegrationService()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        try
        {
            // Add code here to start your service.
            logger.Info($"Starting IntegrationService");

            var updateIntervalString = ConfigurationManager.AppSettings["UpdateInterval"];
            var updateInterval = 60000;
            Int32.TryParse(updateIntervalString, out updateInterval);

            var projectHost = ConfigurationManager.AppSettings["ProjectIntegrationServiceHost"];
            var projectIntegrationApiService = new ProjectIntegrationApiService(new Uri(projectHost));
            var projectDbContext = new ProjectDbContext();
            var projectIntegrationService = new ProjectIntegrationService(projectIntegrationApiService, projectDbContext);
            timer = new System.Timers.Timer();
            timer.AutoReset = true;
            var integrationProcessor = new IntegrationProcessor(updateInterval, projectIntegrationService, timer);
            timer.Start();
        }
        catch (Exception e)
        {
            logger.Fatal(e);
        }
    }

    protected override void OnStop()
    {
        try
        {
            // Add code here to perform any tear-down necessary to stop your service.
            timer.Enabled = false;
            timer.Dispose();
            timer = null;
        }
        catch (Exception e)
        {
            logger.Fatal(e);
        }
    }
}

處理器:

public class IntegrationProcessor
{
    private static Logger _logger = LogManager.GetCurrentClassLogger();
    private static volatile bool _workerIsRunning;
    private int _updateInterval;
    private ProjectIntegrationService _projectIntegrationService;

    public IntegrationProcessor(int updateInterval, ProjectIntegrationService projectIntegrationService, Timer timer)
    {
        _updateInterval = updateInterval;
        _projectIntegrationService = projectIntegrationService;

        timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        timer.Interval = _updateInterval;

        //Don't wait for first elapsed time - Should not be used when running as a service due to that Starting will hang up until the queue is empty
        if (Environment.UserInteractive)
        {
            OnTimedEvent(null, null);
        }
        _workerIsRunning = false;
    }

    private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        try
        {
            if (_workerIsRunning == false)
            {
                _workerIsRunning = true;

                ProjectInformationToGet infoToGet = null;
                _logger.Info($"Started looking for information to get");
                //Run until queue is empty
                while ((infoToGet = _projectIntegrationService.GetInformationToGet()) != null)
                {
                    //Set debugger on logger below to control how many cycles the service should run while debugging.
                    var watch = System.Diagnostics.Stopwatch.StartNew();
                    _logger.Info($"Started Stopwatch");
                    _logger.Info($"Found new information, updating values");
                    _projectIntegrationService.AddOrUpdateNewInformation(infoToGet);
                    _logger.Info($"Completed updating values");
                    watch.Stop();
                    _logger.Info($"Stopwatch stopped. Elapsed seconds: {watch.ElapsedMilliseconds / 1000}. " +
                                 $"Name queue items: {infoToGet.NameQueueItems.Count} " +
                                 $"Case queue items: {infoToGet.CaseQueueItems.Count} " +
                                 $"Fee calculation queue items: {infoToGet.FeeCalculationQueueItems.Count} " +
                                 $"Updated foreign keys: {infoToGet.ShouldUpdateKeys}");
                }

                _logger.Info($"Nothing more to get from integration service right now");

                _workerIsRunning = false;
            }
            else
            {
                _logger.Info($"Worker is already running! Will check back again after {_updateInterval / 1000} seconds");
            }
        }
        catch (DbEntityValidationException exception)
        {
            var newException = new FormattedDbEntityValidationException(exception);
            HandelException(newException);
            throw newException;
        }
        catch (Exception exception)
        {
            HandelException(exception);
            //If an exception occurs when running as a service, the service will restart and run again
            if (Environment.UserInteractive)
            {
                throw;
            }
        }
    }

    private void HandelException(Exception exception)
    {
        _logger.Fatal(exception);
        _workerIsRunning = false;
    }
}

查找服務的PID

sc queryex <SERVICE_NAME>

給出結果如下

SERVICE_NAME: Foo.Services.Bar TYPE : 10 WIN32_OWN_PROCESS STATE : 2 0 START_PENDING (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0x 6 PID 0x70x00x 0x00x 0x00x 0x00x000

現在終止服務:

taskkill /f /pid 3976

成功:PID 為 3976 的進程已終止。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM