在F#中混合IObservable和Async <'a>

时间:2018-09-12 09:38:12

标签: asynchronous f# system.reactive

我有一个图书馆提供的IObservable,该图书馆会监听来自外部服务的事件:

let startObservable () : IObservable<'a> = failwith "Given"

对于每个收到的事件,我要执行一个返回Async的操作:

let action (item: 'a) : Async<unit> = failwith "Given"

我正试图以以下方式实现处理器

let processor () : Async<unit> =
    startObservable()
    |> Observable.mapAsync action
    |> Async.AwaitObservable

我已经组成mapAsyncAwaitObservable:理想情况下,它们将由某个库提供,到目前为止我找不到。

额外要求:

  • 动作应按顺序执行,以便在处理上一个事件时缓冲后续事件。

  • 如果某个动作引发错误,我希望处理器完成。否则,它将永远无法完成。

  • 通过Async.Start传递的取消令牌。

关于我应该使用的库的任何提示吗?

2 个答案:

答案 0 :(得分:5)

由于您要将基于推的模型(IObservable<>)转换为基于拉的模型(Async<>),因此需要排队以缓冲来自可观察的数据。如果队列是受大小限制的,则为-tbh。应该是为了确保整个管道安全,以免使内存不溢出-然后还需要一种用于缓冲区溢出的策略。

  1. 一种方法是实现MailboxProcessor<>和自定义可观察的对象,该方法会将数据发布到其中。由于MP是F#actor的本机实现,因此它能够使用队列进行有序处理,以缓冲峰值。
  2. 另一种选择是使用FSharp.Control.AsyncSeq(特别是AsyncSeq.ofObservableBuffered函数),它将可观察到的基于拉的异步枚举-从第一点开始,它使用邮箱处理器:

    startObservable()
    |> AsyncSeq.ofObservableBuffered
    |> AsyncSeq.iterAsync action
    

答案 1 :(得分:1)

Hopac可以轻松与IObservables互操作 您可以使用Jobs

将Hopac Async转换为Job.toAsync
open System
open Hopac

let startObservable () : IObservable<'a> = failwith "Given"

let action (item: 'a) : Job<unit> = failwith "Given"

let processor () : Job<unit> =
    startObservable()
    |> Stream.ofObservable
    |> Stream.mapJob action
    |> Stream.iter