【问题标题】:1053 Windows Service Error using .NET Core 3.1 Worker Service使用 .NET Core 3.1 Worker 服务时出现 1053 Windows 服务错误
【发布时间】:2020-11-12 19:57:47
【问题描述】:

我创建了一个 Worker 服务,该服务在 Visual Studio 2019 中的调试和发布上均按预期工作。该服务监视要创建的 .csv,并使用正确的编码 (UTF-8) 将其重写到另一个目录。当我发布它并创建 Windows 服务时,在启动 Windows 服务时我收到Error 1053: The service did not respond to the start or control request in a timely fashion。据我了解,我的OnStart 的返回速度不够快。但我不确定如何调试。

程序类

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using System;

namespace SupplyProUTF8service
{
    public class Program
    {
        public static void Main(string[] args)
        {

            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning)
                .Enrich.FromLogContext()
                .WriteTo.File(@"\\REP-APP\temp\workerservice\log.txt", rollingInterval: RollingInterval.Day)
                .CreateLogger();

            try
            {
                Log.Information("Application Started.");
                CreateHostBuilder(args).Build().Run();

            }
            catch (Exception e)
            {

                Log.Fatal(e, "Application terminated unexpectedly");
            }
            finally
            {
                Log.CloseAndFlush();
            }

            CreateHostBuilder(args).Build().Run();

        }


        public static IHostBuilder CreateHostBuilder(string[] args)
            => Host.CreateDefaultBuilder(args).UseWindowsService().ConfigureServices((hostContext, services)
                => { services.AddHostedService<Worker>(); }).UseSerilog();
    }
}

新工人阶级 仍然出现 1053 错误

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace SupplyProUTF8service
{
    public class Worker : BackgroundService
    {

        private readonly string ordrstkPath;
        private readonly string conrstkPath;
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            ordrstkPath = @"\\Rep-app\sftp_root\supplypro\ordrstk";
            conrstkPath = @"\\Rep-app\sftp_root\supplypro\Conrstk";
            _logger = logger;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {

            _logger.LogInformation("SupplyProRewrite Service started");
            return base.StartAsync(cancellationToken);
        }


        private FileSystemWatcher Watch(string path)
        {
            //initialize
            FileSystemWatcher watcher = new FileSystemWatcher
            {

                //assign paramater path
                Path = path,

                //don't watch subdirectories
                IncludeSubdirectories = false
            };

            //file created event
            watcher.Created += FileSystemWatcher_Created;

            //filters
            watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Size | NotifyFilters.Attributes;

            //only look for csv
            watcher.Filter = "*.csv";

            // Begin watching.
            watcher.EnableRaisingEvents = true;

            return watcher;
        }
        private void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {
            _logger.LogInformation("{FullPath} has been created", e.FullPath);
            Thread.Sleep(10000);
            while (!IsFileLocked(e.FullPath))
            {
                ReadWriteStream(e.FullPath, e.Name);
                break;
            }
        }

        private static bool IsFileLocked(string filePath)
        {
            try
            {
                using FileStream originalFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                originalFileStream.Close();
            }
            catch (Exception)
            {
                return true;
            }
            return false;
        }

        private void ReadWriteStream(string path, string fileName)
        {

            string originalPath = path;
            //destination path by replacing SFTP user directory
            string destinationPath = path.Replace(@"\supplypro\", @"\ftpuser\");

            string currentLine;

            using FileStream originalFileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
            using FileStream destinationFileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write);
            using StreamReader streamReader = new StreamReader(originalFileStream);
            using StreamWriter streamWriter = new StreamWriter(destinationFileStream);
            try
            {
                currentLine = streamReader.ReadLine();
                while (currentLine != null)
                {

                    streamWriter.WriteLine(currentLine);
                    currentLine = streamReader.ReadLine();

                }

                streamReader.Close();
                streamWriter.Close();

                //archive path
                string archivePath = path.Replace(fileName, @"archive\" + fileName);

                //move to archive path
                while (!IsFileLocked(originalPath))
                {
                    try
                    {
                        File.Move(originalPath, archivePath, true);
                        _logger.LogInformation("{FileName} moved to archive", fileName);
                        break;
                    }
                    catch (Exception e)
                    {
                        _logger.LogError("Unable to move {fileName} to archive", fileName, e);
                        break;
                    }
                }


            }
            catch (Exception e)
            {
                //error path
                string errorPath = path.Replace(fileName, @"error\" + fileName);

                //move to error path
                while (!IsFileLocked(originalPath))
                {
                    File.Move(path, errorPath);
                    _logger.LogError("{FullPath} file was moved to error", originalPath, e);
                    break;
                }

            }
            finally
            {
                destinationFileStream.Close();
                originalFileStream.Close();

            }
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            using (Watch(ordrstkPath))
            {
                _logger.LogInformation("ordrstk being watched");
                await Task.Delay(Timeout.Infinite, stoppingToken);
            }

            using(Watch(conrstkPath))
            {
                _logger.LogInformation("conrstk being watched");
                await Task.Delay(Timeout.Infinite, stoppingToken);
            }
        }
    }
}

【问题讨论】:

  • 你用错了这个模式。这不是BackgroundService 应该如何工作的。相反,实现 IHostedService 而不是 BackgroundService 并覆盖 StartAsyncStopAsync
  • 您应该使用 ExecuteAsync 而不是 StartAsync 吗?我还没有丰富的 Worker Service 经验,但我拥有的一个程序有点相似,因为它一直在监视,具有 ExecuteAsync 上的所有功能。我认为 StartAsync 代码没有完成,这就是为什么它会给你它的响应?
  • @Andy 完全不正确。 Worker Service 项目的模板(即使用 .NET Core 编写 Windows 服务的方式)生成一个名为 Worker 的类,该类扩展了 BackgroundService,并带有一个用于实现 ExecuteAsync 的存根。
  • @Andy 我有条件地撤回我之前的评论。我所描述的是 MS 现在打算如何完成。但是有这个insidious bug,解决方法是用旧方法。

标签: c# .net-core


【解决方案1】:

我不知道为什么我一开始不这样做。我向那些花时间看这个的人道歉。我最终使用.\WorkerService.exe 在 Powershell 中运行该应用程序。这引发了我缺少 ASP.net Core 运行时的错误。我之前安装了 .NET core 的运行时,最近安装了 5.0。此工作器服务必须需要具有托管运行时的特定 ASP.Net Core:Download。现在开始服务没有问题。

【讨论】:

    【解决方案2】:

    由于FileSystemWatcher 不是async 关键字意义上的异步,而是IDisposable,因此您的ExecuteAsync 可能如下所示:

    protected override async Task ExecuteAsync(CancellationToken cancel)
    {
        using (/* method that sets up and returns your watcher */)
        {
            await Task.Delay(Timeout.Infinite, cancel);
        }
    }
    

    此处未显示,但您可能希望在服务关闭时捕获Task.Delay 抛出的TaskCanceledException

    【讨论】:

    • 好的,所以我的Watch 方法应该在ExecuteAsync 中调用。现在我当前的Watch 方法不返回观察者,它只触发我处理的创建事件。我应该以不同的方式解决这个问题吗?
    • @RyanFreemark 我建议编写一个返回观察者的方法,以便于使代码更具可读性。我的示例代码只是一种确保在服务停止时正确清理观察者的简单方法。
    • 我已将 Watch 方法移至 ExecuteAsync,但在全新发布发布和新服务时仍收到 1053 错误。有没有办法可以调试这个?我很茫然。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 2022-11-09
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    相关资源
    最近更新 更多