播放历史数据Akka Stream

时间:2018-02-07 23:03:04

标签: scala akka-stream

是否可以根据Akka Streams定义的时钟发出数据?或者他们只是在数据到达时发出(忽略背压)?我特别想知道是否可以使用“模拟”时钟回放历史数据,或许可以使用Source.tick

1 个答案:

答案 0 :(得分:1)

这取决于“定义时钟”的含义。

实际停电时间

正如您所提到的,Source.tick是一种从系统时钟获取实际时间的可能性。问题是Sink可能不会以大于或等于Source生成滴答的间隔的速率发出需求信号。例如,您的接收器可能每分钟仅发出一次请求信号,但您在Source.tick中的间隔可能是10 seconds。在这种情况下,将从文档中删除5个中间刻度:

  

如果消费者在某个时间点没有请求任何元素   生成tick元素,它将不会接收该tick元素   后面。

模拟时间

始终可以使用Source来模拟时间。

我们可以先创建一个使用开始时间,结束时间和间隔来模拟时钟的函数:

type MillisFromEpoch = Long

type MillisInterval = Long


val clock : (MillisFromEpoch, MillisFromEpoch, MillisInterval) => () => Iterator[MillisFromEpoch] = 
  (startTime, stopTime, interval) => () => new Iterator[MillisFromEpoch] {
    var currentTime = startTime

    override def hasNext : Boolean = currentTime < stopTime

    override def next() : MillisFromEpoch = {
      val returnMilis = currentTime
      currentTime += interval

      return returnMillis
    }
  }

此时钟现在可以为源提供信号。作为一个例子,我们可以创建一个从unix epoch开始并以1秒递增直到时间结束的时钟:

val epoch : MillisFromEpoch = 0L

val second : MillisInterval = 1000L

val simulatedClockFromEpochSource : Source[MillisFromEpoch,_] = 
  Source fromIterator clock(epoch, Long.MaxValue, 1*second)

或者我们可以创建一个现在开始的时钟,并在60秒内以5秒的间隔递增:

val now : MillisFromEpoch = System.currentTimeMillis()

val simulatedClockFromNowSource : Source[MillisFromEpoch,_] = 
  Source fromIterator clock(now, now + 60*second, 5*second)

采样频率

即使下游消费者比源指定的滴答间隔慢,也可以使用Source.tick。我们可以创建一个Flow.filter,它不断地向Source发出需求信号,但只会传递相隔定义的增量的时间。

我们可以从一个使用内部变量跟踪时间间隔的函数开始:

val frequencySample : (MillisInterval) => (MillisFromEpoch) => Boolean = 
  (interval) => {

    var lastValidTime : MillisFromEpoch = -1

    (timeToCheck) => {
      if(lastValidTime < 0 || timeToCheck >= lastValidTime + interval) {
        lastValidTime = timeToCheck

        true
      }
      else {
        false
      }
    }
  }

现在这个函数可以用来创建Flow:

val frequencySampleFlow : (MillisInterval) => Flow[MillisFromEpoch, MillisFromEpoch, _] =
  (frequency) => Flow[MillisFromEpoch]  filter frequencySample(frequency)

现在我们可以创建一个具有较慢频率(例如10秒)的流量,该流量附加到频率较高的源(例如1秒):

val slowFrequency : MillisInterval = 10 * second

//simulatedClockFromEpoch ticks every 1 second
//frequnencySampleFlow only passes every 10 second tick through
val slowSource = 
  simulatedClockFromEpochSource via frequencySampleFlow(slowFrequency)