【问题标题】:How to integrate TPL Dataflow in ASP NET Core如何在 ASP NET Core 中集成 TPL 数据流
【发布时间】:2020-06-07 07:54:24
【问题描述】:

您好最近对TPL Dataflow 产生了浓厚的兴趣,我想将它集成到我的ASP .NET Core 应用程序中。 我想将它用作管道,来自应用程序不同部分的多个方法可以将数据发布到这个 DataFlow 链。 我不知道的是,如果您希望从多个地方调用它们,您将块链接存储在哪里?

制片人

public class Producer
{
    private BufferBlock<int> startBlock{get;}
    private ActionBlock<int> ioBlock{get;}
    private IOService service;

    private void InitializeChain()
    {
       this.startBlock=new BufferBlock<int>();
       var transformLink=new TransformBlock<int,string>([something]);
       // some chain of blocks here 
       this.ioBlock=new ActionBlock<int>(async(x)=>await this.service.WriteAsync(x));
       this.startBlock.LinkTo([someBlock]).LinkTo([someOtherBlock])......LinkTo(ioBlock);
    }
    public async Task AddAsync(int data)
    {
        this.BufferBlock.Post(data);
    }
    public Producer(IOService service)
    {
        this.service=service;
        this.InitializeChain();
    }
}

API 生产者
我设想这个 Producer 会从我的应用程序的多个部分调用,为了简洁起见,请使用 Controller-s:

public class C1:Controller
{
    private Producer producer;
    [HttpPost]
    [Route([someroute])
    public async Task SomeRoute(int data)
    {
        await  this.producer.AddAsync(data);
    }
    [HttpGet]
    [Route([someotherroute])
    public async Task SomeOtherRoute(int data)
    {
        await  this.producer.AddAsync(data);
    }
    public C1(Producer producer)
    {
      this.producer=producer;
    }
}

启动

  public void ConfigureServices(IServiceCollection services) {
           services.AddSingleton<Producer>();
  }

这可以扩展到多个Controller 场景或更深的层次结构。

现在我的问题是:
保持Dataflow 链的Producer 应该如何注入?它应该是暂时的吗? Blocks 是否应该在每次调用时实例化?

不知道这个设计好不好。我知道 TPL Dataflow 是线程安全的,但是可以这样用吗?

P.S如果我希望它在我的ASP NET Core 应用程序的整个范围内可用,我基本上不知道以什么形式保留我的Dataflow 管道及其生命周期。 我想从多个端点(直接或更深地调用层次结构)获取数据,对它们进行批处理,转换它们,并控制它们最终写入外部源的方式(async 操作)。 这与现有的ThreadPoolASP NET Core 配合得好吗?

P.S 2:这个问题也困扰着我,因为Rx 等价物。

【问题讨论】:

  • 这个管道是打算在每个 Web 请求上创建,还是打算在应用程序方面,并在应用程序的整个生命周期内持久保存在内存中?在第二种情况下,我建议看看这个:Fire and Forget on ASP.NET。 TL;DR 您的管道可能会随着应用程序频繁且不确定地被回收。
  • 我认为它适合第二种情况,因为我希望这个管道创建一次,然后在我的应用程序中的任何地方使用。我需要一个我的所有数据进入的地方(通过我的应用程序)得到转换,聚合然后分批写入其他地方(也许)。还有你说的回收是什么意思?如果我使用单例对象,它不会在所有应用程序生命周期中持续存在吗?
  • AFAIK 单例对象将无法在 ASP.NET 中的 AppDomain 卸载/重新加载或 w3wp.exe 进程的回收中存活。不知道 ASP.NET Core 有没有区别。以下是一些可能有用的链接:123
  • 这取决于管道完成的工作类型。例如,如果它产生了一些不重要的统计数据,那么我想时不时丢失一些数据不会是什么大问题。
  • 如果偶尔数据无法在底层存储介质中持久化会不会有问题?客户端是否能够稍后确认数据实际上已被持久化,如果不能再次尝试发送它们?

标签: asp.net-core tpl-dataflow


【解决方案1】:

我建议不要将控制器直接链接到后台处理器。出于可靠性原因,它们之间应该有一个持久队列。这可以是 Azure 队列、Amazon 简单队列,甚至是 MSMQ 或数据库之类的老派。

您的处理器可以是独立的(Azure Function、Amazon Lambda 或类似 Win32 服务的老派),也可以是您的 Web 应用程序的一部分(ASP.NET Core 托管服务)。

您的控制器写入持久队列,然后返回。然后,您的处理器从队列中读取消息并进行处理。您的处理器将使用 TPL Dataflow 或 Rx - 以更自然的为准。

【讨论】:

  • 我确实有一个持久队列:Redis。我现在严格指的是生产者端。我将处理器视为单例服务,其唯一目的是将消息发布到Redis 通道。它的肚子我要么使用 TPL 数据流,要么将消息推送到与循环协同工作的 ConcurrentQueue,该循环将从所述队列中获取并发布到 Redis。我不想通过 await-ing Redis 写入来阻止调用者的执行方法.你觉得制作方这一层是不必要的吗?消费者将是您提到的托管服务。
  • 在数据持久化之前返回,你将失去持久化队列的所有好处。我强烈建议不要早早返回并直接写到 Redis。
  • 这部分正在引发标志:I do not want to block the caller's executing method by await-ing the Redis write. - 控制器必须等待直到工作被持久化;这就是持久队列的全部意义所在。如果控制器返回并将持久化留给其他代码,那么您将失去持久化队列的好处。
  • 我想我只是想避免这句话altering a system by the mere observance of it
猜你喜欢
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
  • 2021-03-04
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
  • 1970-01-01
相关资源
最近更新 更多