簡體   English   中英

錯誤1053:服務沒有響應 C#.Net Core 3.1

[英]Error 1053: Service did not respond C# .Net Core 3.1

我正在嘗試將自己的 C# 服務作為 Windows 服務啟動。 我使用sc.exe create安裝了我的服務。 我可以在服務應用程序中查看和修改服務,但是當我嘗試啟動時,我總是收到錯誤 1053。在我的程序中,我正在啟動一個新線程,該線程在執行中運行無限循環。

static void Main(string[] args) {
    Console.WriteLine("Starting Thread");

    mainThread = new Thread(new ThreadStart(Execute));
    mainThread.Start();

    Console.WriteLine("Thread Started!");
}

public static void Execute() {
    //connect to Database

    while(true) { //while connection open
        ...
    }
}

當我在控制台 Powershell 和 Visual Studio 中手動運行程序時,程序按預期運行。 當我嘗試通過服務運行它時,出現錯誤。 當我運行一個空的 Main(Main 僅使用 Console.WriteLine)時,我也遇到了錯誤。 我在谷歌上搜索了很多,並嘗試在注冊表中延長超時時間(ServicesPipeTimeout),使用線程,安裝核心框架,重新安裝服務並成為服務的所有者。

編輯:我更改了所有內容以作為托管服務運行。 在我的主要我有

await new HostBuilder()
            .ConfigureServices((hostContext, services) => { services.AddHostedService<Worker>(); })
            .Build()
            .RunAsync();

但我仍然無法將其作為 Windows 服務運行,我遇到了同樣的錯誤。

我沒有想法,非常感謝任何幫助。

問候

你寫的是一個標准的控制台應用程序。 服務應公開啟動和停止設施以由 Windows(或等效的 SystemD)正確解釋。

main 的核心循環應該托管在 IHostedService 或 Worker 服務上。 看看 [這里][1] 來弄清楚你必須做什么。

我在下面給你一個似是而非的 Program.cs 文件,我之前為 Linux 服務編寫的(實際上與 Windows 服務沒有區別,只是刪除了.UseSystemD()調用)。

/// <summary>
///     Remote service App for Monday Parser and Database manager.
/// </summary>
public static class Program
{
    private static readonly ILogger logger = new LoggerConfiguration()
            .ReadFrom.Configuration(MondayConfiguration.Configuration, sectionName: "AppLog")
        .CreateLogger().ForContext("Origin", "MondayService");

    /// <summary>
    ///     Helper to create hosting environment.
    /// </summary>
    /// <param name="args">
    ///     command line arguments if any- no management is occurring now.
    /// </param>
    /// <returns>
    /// </returns>
    public static IHostBuilder CreateWebHostBuilder(string[] args)
    {
        string curDir = MondayConfiguration.DefineCurrentDir();
        IConfigurationRoot config = new ConfigurationBuilder()

            // .SetBasePath(Directory.GetCurrentDirectory())
            .SetBasePath(curDir)
            .AddJsonFile("servicelocationoptions.json", optional: false, reloadOnChange: true)
#if DEBUG
               .AddJsonFile("appSettings.Debug.json")

#else
               .AddJsonFile("appSettings.json")
#endif
               .Build();
        return Host.CreateDefaultBuilder(args)
            .UseContentRoot(curDir)
            .ConfigureAppConfiguration((_, configuration) =>
            {
                configuration
                .AddIniFile("appSettings.ini", optional: true, reloadOnChange: true)
#if DEBUG
               .AddJsonFile("appSettings.Debug.json")

#else
               .AddJsonFile("appSettings.json")
#endif
                .AddJsonFile("servicelocationoptions.json", optional: false, reloadOnChange: true);
            })

            .UseSerilog((_, services, configuration) => configuration
                .ReadFrom.Configuration(config, sectionName: "AppLog")// (context.Configuration)
                .ReadFrom.Services(services)
                .Enrich.FromLogContext()
                .WriteTo.Console())

            // .UseSerilog(MondayConfiguration.Logger)
            .ConfigureServices((hostContext, services) =>
            {
                services
                .Configure<ServiceLocationOptions>(hostContext.Configuration.GetSection(key: nameof(ServiceLocationOptions)))
                .Configure<HostOptions>(opts => opts.ShutdownTimeout = TimeSpan.FromSeconds(30));
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
                ServiceLocationOptions? locationOptions = config.GetSection(nameof(ServiceLocationOptions)).Get<ServiceLocationOptions>();
                string url = locationOptions?.HttpBase + "*:" + locationOptions?.Port;
                webBuilder.UseUrls(url);
            })
            .UseSystemd();
    }

您可以在下面找到服務的主要實現,我添加了很多 XML 來向您展示在服務中移動內容時可能遇到的所有異常,以及應該至少實現哪些方法才能使服務正常工作。

如果您刪除所有您不了解的變量,您將保留 windows 服務的工作框架,該服務僅運行一個 ping 服務。 試試吧。

/// <summary>
///     Main Worker class for managing the service inside SystemD.
/// </summary>
public partial class MondayService : BackgroundService
{
    /// <summary>
    ///     Initializes a new instance of the <see cref="MondayService"/> class. Std ctr.
    /// </summary>
    /// <param name="mondayhub">
    /// </param>
    /// <param name="containerServer">
    /// </param>
    public MondayService(IHubContext<MondayHub, IMondayServiceHub> mondayhub,
       IFeatureContainer containerServer)
    {
        _containerServer = containerServer;
        _dbManager = _containerServer.DbManager;
        _parser = _containerServer.Parser;
        _syslogQueue = _containerServer.SyslogQueue;
        _segmentManager = _containerServer.SegmentManager;
        _orderManager = _containerServer.OrderManager;

        while (!MondayConfiguration.SerilogFactoryReady)
        {
            Thread.Sleep(20);
        }

        // _logger = MondayConfiguration.LoggerFactory.CreateLogger("");
        _logger = new LoggerConfiguration().ReadFrom.Configuration(MondayConfiguration.Configuration, sectionName: "AppLog").CreateLogger().ForContext("Origin", "MondayService");
        _mondayHub = mondayhub;
    }

    /// <summary>
    ///     Setup activities for the Monday service.
    /// </summary>
    /// <param name="cancellationToken">
    /// </param>
    /// <returns>
    /// </returns>
    /// <exception cref="OverflowException">
    ///     <paramref><name>value</name></paramref> is less than <see cref="TimeSpan.MinValue"/>
    ///     or greater than <see cref="TimeSpan.MaxValue"/>.
    ///     -or- value is <see><cref>System.Double.PositiveInfinity</cref></see> .
    ///     -or- value is <see cref="double.NegativeInfinity"/>.
    /// </exception>
    /// <exception cref="AggregateException">
    ///     The task was canceled. The <see><cref>InnerExceptions</cref></see> collection
    ///     contains a <see cref="TaskCanceledException"/> object.
    ///     -or- An exception was thrown during the execution of the task. The
    ///      <see><cref>InnerExceptions</cref></see> collection contains information about the
    ///     exception or exceptions.
    /// </exception>
    /// <exception cref="TaskCanceledException">
    ///     The task has been canceled.
    /// </exception>
    /// <exception cref="ArgumentNullException">
    ///     The <paramref><name>function</name></paramref> parameter was <see langword="null"/>.
    /// </exception>
    /// <exception cref="ObjectDisposedException">
    ///     The <see cref="CancellationTokenSource"/> associated with <paramref
    ///     name="cancellationToken"/> was disposed.
    /// </exception>
    /// <exception cref="IOException">
    ///     destFileName already exists and overwrite is <see langword="false"/>.
    ///     -or- An I/O error has occurred, e.g. while copying the file across disk volumes.
    /// </exception>
    /// <exception cref="UnauthorizedAccessException">
    ///     The caller does not have the required permission.
    /// </exception>
    /// <exception cref="SecurityException">
    ///     The caller does not have the required permission.
    /// </exception>
    /// <exception cref="FileNotFoundException">
    ///     <paramref><name>sourceFileName</name></paramref> was not found.
    /// </exception>
    public override Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.DebugInfo().Information("MondayService: Starting StartAsync");
        var parserRenewed = false;
        if (_parser is null)
        {
            _parser = new();
            _parser.OnParserSocketDataArrived +=
                (sender, e) => _containerServer.BroadcastParserSocketDataViaSignalR(sender, e);
            parserRenewed = true;
            Task.Run(ParserSubscriptions, cancellationToken);
            _logger.DebugInfo().Information("MondayService: Instantiating again the parser inside StartAsync");
        }

        if (_dbManager is null || parserRenewed)
        {
            _dbManager = new(_parser);
            _logger.DebugInfo().Information("MondayService: Instantiating again the db manager inside StartAsync");
            _dbManager.ConnectToParserSocket();
            _dbManager.OnFilteredSocketDataArrived +=
                (sender, e) => _containerServer.BroadcastFilteredSocketDataViaSignalR(sender, e);
            if (!_tagsDataSavedOnce)
            {
                // ReSharper disable once ExceptionNotDocumented
                Tags.SaveAll();
                _tagsDataSavedOnce = true;
            }
        }

        if (_segmentManager is null)
        {
            _segmentManager = new(_parser, _dbManager);
            _segmentManager.ConnectToParserSocket(_parser);
            _segmentManager.OnSegmentClosure += (sender, e) => _containerServer.BroadcastSegmentDataViaSignalR(sender, e);
            _logger.DebugInfo().Information("MondayService: Instantiating again the segment manager inside StartAsync");
        }

        if (_orderManager is null)
        {
            _orderManager = new(_parser);
            _orderManager.OnOrderManagerEvent +=
                (sender, e) => _containerServer.BroadcastOrderManagerEventsViaSignalR(sender, e);
            _logger.DebugInfo().Information("MondayService: Instantiating again the order manager inside StartAsync");
        }

        _logger.DebugInfo().Information("MondayService: Completing StartAsync");
        return base.StartAsync(cancellationToken);
    }

    /// <summary>
    ///     Graceful shutdown and disposal of Monday service (parser and database manager comprised).
    /// </summary>
    /// <param name="cancellationToken">
    /// </param>
    /// <returns>
    /// </returns>
    /// <exception cref="IOException">
    ///     destFileName already exists and overwrite is <see langword="false"/>.
    ///     -or- An I/O error has occurred, e.g. while copying the file across disk volumes.
    /// </exception>
    /// <exception cref="UnauthorizedAccessException">
    ///     The caller does not have the required permission.
    /// </exception>
    /// <exception cref="AggregateException">
    ///     The task was canceled. The <see><cref>InnerExceptions</cref></see> collection
    ///     contains a <see cref="TaskCanceledException"/> object.
    ///     -or- An exception was thrown during the execution of the task. The
    ///      <see><cref>InnerExceptions</cref></see> collection contains information about the
    ///     exception or exceptions.
    /// </exception>
    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.DebugInfo().Information("MondayService: Starting StopAsync");
        if (!_tagsDataSavedOnce)
        {
            Tags.SaveAll();
            _tagsDataSavedOnce = true;
        }

        _logger.DebugInfo().Information("Stopping Monday Service hosted on Linux.");
        if (_parser is not null) await _parser.UnsubscribeAllAsync();
        foreach (string ex in Tags.Exchanges.ExchangeNames.ToList())
        {
            _parser?.DeactivateRest(ex);
        }

        _parser?.Dispose();
        _dbManager?.Dispose();
        _orderManager?.Dispose();
        _segmentManager?.Dispose();
        _logger.DebugInfo().Information("MondayService: Completing StopAsync");
        await base.StopAsync(cancellationToken);
    }

    /// <summary>
    ///     Core loop of the service. Here all the assets are instantiated and managed up to
    ///     final disposal. This instantiates the SignalR service and manages it.
    /// </summary>
    /// <param name="stoppingToken">
    /// </param>
    /// <returns>
    /// </returns>
    /// <exception cref="TaskCanceledException">
    ///     The task has been canceled.
    /// </exception>
    /// <exception cref="ArgumentOutOfRangeException">
    ///     <paramref><name>delay</name></paramref> represents a negative time interval other
    ///     than <see langword="TimeSpan.FromMilliseconds(-1)"/>.
    ///     -or- The <paramref><name>delay</name></paramref> argument's <see
    ///      cref="P:System.TimeSpan.TotalMilliseconds"/> property is greater than <see cref="int.MaxValue"/>.
    /// </exception>
    /// <exception cref="ObjectDisposedException">
    ///     The provided <paramref><name>cancellationToken</name></paramref> has already been disposed.
    /// </exception>
    /// <exception cref="OverflowException">
    ///     <paramref><name>value</name></paramref> is less than <see cref="TimeSpan.MinValue"/>
    ///     or greater than <see cref="TimeSpan.MaxValue"/>.
    ///     -or- <paramref><name>value</name></paramref> is <see cref="double.PositiveInfinity"/>.
    ///     -or- <paramref><name>value</name></paramref> is <see cref="double.NegativeInfinity"/>.
    /// </exception>
    /// <exception cref="IOException">
    ///     destFileName already exists and overwrite is <see langword="false"/>.
    ///     -or- An I/O error has occurred, e.g. while copying the file across disk volumes.
    /// </exception>
    /// <exception cref="UnauthorizedAccessException">
    ///     The caller does not have the required permission.
    /// </exception>
    /// <exception cref="SecurityException">
    ///     The caller does not have the required permission.
    /// </exception>
    /// <exception cref="FileNotFoundException">
    ///     <paramref><name>sourceFileName</name></paramref> was not found.
    /// </exception>
    /// <exception cref="DirectoryNotFoundException">
    ///     The specified path is invalid (for example, it is on an unmapped drive).
    /// </exception>
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.DebugInfo().Information("Monday Service starting at {Now}", DateTimeOffset.Now);
        while (!stoppingToken.IsCancellationRequested)
        {
            Task tlog = FetchLogAsync(stoppingToken);
            Task? tping = null;
            int seconds = DateTimeOffset.Now.Second;
            int minutes = DateTimeOffset.Now.Minute;

            // logging a ping every 5 minutes
            if (seconds < 5 && minutes % 1 == 0)
            {
                tping = Ping();
                if (!_tagsDataSavedOnce)
                {
                    Tags.SaveAll();
                    _tagsDataSavedOnce = true;
                }
            }

            // looping every 5 seconds
            var tLoop = Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
            if (tping is null)
            {
                await Task.WhenAll(tlog, tLoop);
            }
            else
            {
                await Task.WhenAll(tlog, tLoop, tping);
            }
        }

        _logger.DebugInfo().Information("Monday Service stopping at {Now}", DateTimeOffset.Now);
    }

    [MustUseReturnValue]
    private Task FetchLogAsync(CancellationToken stoppingToken)
    {
        var ok = true;
        while (ok)
        {
            try
            {
                ok = _containerServer.SyslogQueue.Reader.TryRead(
                    out (LogLevel lvl, string line) item);
                if (ok)
                {
                    switch (item.lvl)
                    {
                        case LogLevel.Trace:

                        case LogLevel.Debug:
                            _logger.DebugInfo().Debug("{FetchedMessage}", item.line);
                            break;

                        case LogLevel.Information:
                            _logger.DebugInfo().Information("{FetchedMessage}", item.line);
                            break;

                        case LogLevel.Warning:
                            _logger.DebugInfo().Warning("{FetchedMessage}", item.line);
                            break;

                        case LogLevel.Error:
                            _logger.DebugInfo().Error("{FetchedMessage}", item.line);
                            break;

                        case LogLevel.Critical:
                            _logger.Fatal("{FetchedMessage}", item.line);
                            break;

                        case LogLevel.None:
                            break;
                    }
                }

                if (stoppingToken.IsCancellationRequested)
                {
                    ok = false;
                }
            }
            catch
            {
                ok = false;
            }
        }

        return Task.CompletedTask;
    }

    private Task<CallResult<UpdateSubscription>> ParserSubscriptions()
    {
        Guard.Against.Null(nameof(_parser));
        return _parser!.SubscribeFromSettingsAsync();
    }

    private async Task Ping()
    {
        await _containerServer.SyslogQueue.Writer.WriteAsync((
            LogLevel.Information,
            $"Monday Service active at: {DateTime.UtcNow.ToLocalTime()}"));
    }

    /// <summary>
    ///     This is a debug utility to check whether the service creates too many ThreaPpool threads.
    /// </summary>
    public static class ProcessTracker
    {
        static ProcessTracker()
        {
        }

        /// <summary>
        ///     See https://stackoverflow.com/questions/31633541/clrmd-throws-exception-when-creating-runtime/31745689#31745689
        /// </summary>
        /// <returns>
        /// </returns>
        public static string Scan()
        {
            StringBuilder sb = new();
            StringBuilder answer = new();
            answer.Append("Active Threads").Append(Environment.NewLine);
            // Create the data target. This tells us the versions of CLR loaded in the target process.
            int countThread = 0;

            var pid = Environment.ProcessId;
            using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive))
            {
                // Note I just take the first version of CLR in the process. You can loop over
                // every loaded CLR to handle the SxS case where both desktop CLR and .Net Core
                // are loaded in the process.
                ClrInfo version = dataTarget.ClrVersions[0];
                var runtime = version.CreateRuntime();
                // Walk each thread in the process.
                foreach (ClrThread thread in runtime.Threads)
                {
                    try
                    {
                        sb = new();
                        // The ClrRuntime.Threads will also report threads which have recently
                        // died, but their underlying data structures have not yet been cleaned
                        // up. This can potentially be useful in debugging (!threads displays
                        // this information with XXX displayed for their OS thread id). You
                        // cannot walk the stack of these threads though, so we skip them here.
                        if (!thread.IsAlive)
                            continue;

                        sb.Append("Thread ").AppendFormat("{0:X}", thread.OSThreadId).Append(':');
                        countThread++;
                        // Each thread tracks a "last thrown exception". This is the exception
                        // object which !threads prints. If that exception object is present, we
                        // will display some basic exception data here. Note that you can get
                        // the stack trace of the exception with ClrHeapException.StackTrace (we
                        // don't do that here).
                        ClrException? currException = thread.CurrentException;
                        if (currException is ClrException ex)
                        {
                            sb.Append("Exception: ")
                                                            .AppendFormat("{0:X}", ex.Address)
                                                            .Append(" (").Append(ex.Type.Name)
                                                            .Append("), HRESULT=")
                                                            .AppendFormat("{0:X}", ex.HResult)
                                                            .AppendLine();
                        }

                        // Walk the stack of the thread and print output similar to !ClrStack.
                        sb.AppendLine(" ------>  Managed Call stack:");
                        var collection = thread.EnumerateStackTrace().ToList();
                        foreach (ClrStackFrame frame in collection)
                        {
                            // Note that CLRStackFrame currently only has three pieces of data:
                            // stack pointer, instruction pointer, and frame name (which comes
                            // from ToString). Future versions of this API will allow you to get
                            // the type/function/module of the method (instead of just the
                            // name). This is not yet implemented.
                            sb.Append("           ").Append(frame).AppendLine();
                        }
                    }
                    catch
                    {
                        //skip to the next
                    }
                    finally
                    {
                        answer.Append(sb);
                    }
                }
            }
            answer.Append(Environment.NewLine).Append(" Total thread listed: ").Append(countThread);
            return answer.ToString();
        }
    }
}

主要的核心循環正在 ping 隊列以進行日志記錄。 這只是一種讓某些東西在服務上永久運行而其他類完成它們的工作的方法(在這種情況下它們幾乎都基於 EAP)。

當然,首先看看MSDN。 看來您缺少基礎知識。 [1]: https://learn.microsoft.com/en-us/do.net/core/extensions/workers

我最終將其編寫為 Windows 服務。 我只是簡單的繼承了ServiceBase,寫了Start和Stop方法。 start 方法啟動一個 Timer,它每分鍾調用一個無限循環的方法。 請參閱: 錯誤 1053:服務未及時響應

暫無
暫無

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

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