.net核心工作人员服务中有多个工作人员?

时间:2019-10-04 03:08:19

标签: .net-core

点网核心3.0工人服务模板如下所示:

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>();
            });
}

“ Worker”类派生自BackgroundService。每隔1000毫秒就会循环将日志写入控制台。

我的问题:

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

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

2 个答案:

答案 0 :(得分:10)

您可以有一个“父母”工人像这样启动“真正”工人...

        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());
            }
        }

然后...

        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);
            }
        }

_config从appSettings.json填充并像这样传递给Worker的构造函数...

var cfg = hostContext.Configuration.GetSection(nameof(WorkerConfig)).Get<WorkerConfig>();
services.AddSingleton(cfg);
services.AddHostedService<Worker>();

和appSettings ...

{
  "WorkerConfig": {
    "LoopIntervals": [ 1000, 2000, 3000 ]
  }
}

答案 1 :(得分:0)

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

我检查了“ AddHostedService”的github源,发现它的实现方式如下:

services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, THostedService>());

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


解决方案:

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

services.AddSingleton<IHostedService, Worker>();
services.AddSingleton<IHostedService, Worker>();

有效。


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

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

services.AddSingleton<IHostedService>(sp => new Worker(sp.GetService<ILogger<Worker>>(), 1000));
services.AddSingleton<IHostedService>(sp => new Worker(sp.GetService<ILogger<Worker>>(), 2000));