Rx,TPL数据流和Windows服务

时间:2018-04-19 12:29:23

标签: c# windows-services system.reactive tpl-dataflow

使用Rx和数据流与Windows服务不断工作是否是个好主意? 我只是想知道使用rx interval每5分钟从db获取数据并将其放入阻塞集合然后使用Tpl数据流来处理数据。这是正确的方法吗?

更新

我有新问题。我必须从db获取项目,验证它并在db上执行commit。即使验证返回false,我也必须执行commit。现在,我想以5分钟的间隔从db获取数据,但我不希望在dataFlow中有双行。所以我必须使用blockingCollection来保持行ID吗?

1 个答案:

答案 0 :(得分:1)

不完全。

首先,您根本不需要BlockingCollection。数据流块具有自己的线程安全输入缓冲区。

其次,块也意味着使用自己的任务执行,这使得它们适合于运行调用数据库和处理结果等操作。另一方面,Rx用于处理通常使用单个线程完成的事件流。

也就是说,您可以组合Rx和Dataflow块。我正在使用Dataflow管道

其次,Rx旨在处理事件流。为此,它通常在当前线程上运行。

也就是说,您可以组合Rx和数据流块。将区间序列与块组合很容易:

var block=new ActionBlock<int>(i=>whatever(i));
var blockObs=blockObs.AsObserver();
var interval=Observable.Interval(obs).Subscribe(obs);

使用数据库需要更多块。假设您要处理单个行,第一个块应该接收触发器,加载数据并返回行。第二个块应该接收各个行并处理它们。

假设您使用Dapper将行作为对象返回:

 var headBlock=new TransformManyBlock<int,SomeRow>(_=>
    {
        using(var con=new SqlConnection(..whatever))
        {
            var items=con.ExecuteQuery(theQuery);
            return itmes;
        }
    });

 var secondBlock = new ActionBlock<SomeRow>(row=>DoSomething(row), 
                          new ExecutionDatalfowBlockOptions{MaxDegreeOfParalelism=10});

 headBlock.LinkTo(secondBlock,new DataFlowLinkOptions{PropagateCompletion=true});

 var headObs=headBlock.AsObserver();

 Observable.Interval(TimeSpan.FromMinutes(1)).Subscribe(headObs);

这只是一个演示。您应该添加代码以在关闭服务器时停止管道并等待任何挂起的操作完成。

您还应该添加错误处理代码,即使发生错误也可以继续处理。如果未处理异常,则抛出的块将终止。如果您返回“包装”结果,并使用指示成功或失败的标志,则可以处理此问题。 LinkTo接受一个谓词,您可以使用该谓词将失败的消息/行移动到记录器或丢弃它们,例如:

var loggerBlock=new ActionBlock<RowWithFlag>(row=>_log.Error(...));

headBlock.LinkTo(secondBlock,linkOptions,row=>row.IsOK);
headBlock.LinkTo(loggerBlock,linkOptions,row=>!row.IsOK);