鉴于我有很长时间的事件流,如下所示。经过很长时间后,将会有很多不再需要的子流。
有没有办法在给定时间清理特定的子流,为 例如,应该清除由id 3创建的子流和状态 扫描方法丢失在13Pm(Wid的属性到期)?
case class Wid(id: Int, v: String, expires: LocalDateTime)
test("Substream with scan") {
val (pub, sub) = TestSource.probe[Wid]
.groupBy(Int.MaxValue, _.id)
.scan("")((a: String, b: Wid) => a + b.v)
.mergeSubstreams
.toMat(TestSink.probe[String])(Keep.both)
.run()
}
答案 0 :(得分:5)
TL; DR 您可以在一段时间后关闭子流。但是,使用输入来动态设置内置阶段的时间是另一回事。
关闭子流
要关闭流程,您通常会完成它(从上游),但您也可以取消它(从下游)。例如,一旦take(n: Int)
元素通过,n
流将取消。
现在,在groupBy
情况下,您无法完成子流,因为上游由所有子流共享,但您可以取消它。具体取决于你希望在什么条件下结束。
但请注意,groupBy
会删除已关闭的子流的输入:如果3
的新元素来自groupBy
之后的3
-substream已经关闭,它将被简单地忽略,下一个元素将被拉入。原因可能是在关闭和重新打开子流之间的过程中可能会丢失一些元素。此外,如果您的流应该运行很长时间,这将影响性能,因为在转发到相关(实时)子流之前,将针对关闭的子流列表检查每个元素。如果您对此表现不满意,您可能希望实现自己的状态过滤器(例如,使用布隆过滤器)。
要关闭一个子流,我通常使用take
(如果你只想要一定数量的元素,但在无限流上可能不是这种情况),或某种超时:{{1如果你想要从物化到关闭的固定时间,或者completionTimeout
,如果你想在没有元素通过一段时间后关闭。请注意,这些流不会取消流但会使其失败,因此您必须使用idleTimeout
或recover
阶段捕获异常,才能将失败更改为取消(recoverWith
允许您通过recoverWith
恢复,取消而不发送任何最后一个元素。
动态设置超时
现在你想要的是根据第一个传递元素动态设置关闭时间。这更复杂,因为流的实现与通过它们的元素无关。实际上,在通常的情况下(没有Source.empty
)情况下,流在任何元素通过之前都已实现,因此使用元素来实现它们是没有意义的。
我在that question中遇到了类似的问题,最后使用了带有签名的groupBy
修改版
groupBy
允许使用定义它的键定义每个子流。可以将其修改为将第一个元素(而不是键)作为参数。
另一种(在您的情况下可能更简单)方式是编写您自己的舞台,完全符合您的要求:从第一个元素获取结束时间并在那时取消流。这是一个示例实现(我使用调度程序而不是设置状态):
paramGroupBy[K, OO, MM](maxSubstreams: Int, f: Out => K, paramSubflow: K => Flow[Out, OO, MM])