.net 核心工作者服务中的多个工作者?

Ray*_*ong 9 .net-core

dot net core 3.0 worker 服务模板如下图所示:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices(services =>
            {
                services.AddHostedService<Worker>();
            });
}
Run Code Online (Sandbox Code Playgroud)

“Worker”类派生自 BackgroundService。它每 1000 毫秒循环一次将日志写入控制台。

我的问题:

我可以同时运行多个“工人”吗?(我知道我可以创建另一个类“Worker2”。但是我可以运行同一个类“Worker”的两个副本吗?)

如果是,我如何配置两个具有不同配置或参数的“工人”,例如,两个具有不同循环间隔的工人?(因为“Worker”类的实例是由DI框架创建的。我不知道如何将不同的配置/参数传递给“Worker”的两个不同实例)

Ed *_*ald 15

You can have a "parent" worker that launches the "real" workers like this...

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                var workers = new List<Task>();
                foreach(var delay in _config.LoopIntervals)
                    workers.Add(DoRealWork(delay, stoppingToken));

                await Task.WhenAll(workers.ToArray());
            }
        }
Run Code Online (Sandbox Code Playgroud)

Then...

        private async Task DoRealWork(int delay, CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("worker {delay} checking in at {time}", delay, DateTimeOffset.Now);
                await Task.Delay(delay, stoppingToken);
            }
        }
Run Code Online (Sandbox Code Playgroud)

_config gets populated from appSettings.json and passed in to the constructor of the Worker like this...

var cfg = hostContext.Configuration.GetSection(nameof(WorkerConfig)).Get<WorkerConfig>();
services.AddSingleton(cfg);
services.AddHostedService<Worker>();
Run Code Online (Sandbox Code Playgroud)

and the appSettings...

{
  "WorkerConfig": {
    "LoopIntervals": [ 1000, 2000, 3000 ]
  }
}
Run Code Online (Sandbox Code Playgroud)


Ray*_*ong 11

“AddHostedService”不接受同一个类注册两次的原因:

我查了“AddHostedService”的github源码,发现是这样实现的:

services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, THostedService>());
Run Code Online (Sandbox Code Playgroud)

根据“TryAddEnumerable”方法的 Microsoft 文档,仅当集合不包含相同服务和实现类型的其他注册时才添加服务。这就是为什么我不能运行“Worker”的两个副本的原因。(故意使用“TryAddEnumerable”来避免为同一服务创建多个实例。参考:https : //github.com/aspnet/Extensions/issues/1078


解决方案:

所以我可以直接使用“AddSingleton”添加两个工人......

services.AddSingleton<IHostedService, Worker>();
services.AddSingleton<IHostedService, Worker>();
Run Code Online (Sandbox Code Playgroud)

有用。


将参数传递给服务构造函数:

然后,我通过为循环间隔添加第二个参数来修改 Worker 类构造函数。最后,我在注册服务时使用实现工厂如下

services.AddSingleton<IHostedService>(sp => new Worker(sp.GetService<ILogger<Worker>>(), 1000));
services.AddSingleton<IHostedService>(sp => new Worker(sp.GetService<ILogger<Worker>>(), 2000));
Run Code Online (Sandbox Code Playgroud)

  • 这真的很棒我有同样的情况,这解决了我的问题 (3认同)