Apache flink 如何使用Flink MiniCluster触发ProcessTimeTimer

Apache flink 如何使用Flink MiniCluster触发ProcessTimeTimer,apache-flink,flink-streaming,Apache Flink,Flink Streaming,我有一个FlinkKeyedCoProcessFunction,它在一个更大的Flink流作业中注册处理时间计时器,我正在尝试使用Flink为整个作业创建单元测试。但是我无法在KeyedCoProcessFunction中获得要触发的onTimer()回调 有人用过这个吗?它需要特殊配置吗 切换到事件时间工作正常,所以我想知道这是否在Flink MiniCluster中不起作用,或者我的实现是否有问题 我用Scala编写了一个简单的测试,看看是否可以让它工作 import org.apache.

我有一个Flink
KeyedCoProcessFunction
,它在一个更大的Flink流作业中注册处理时间计时器,我正在尝试使用Flink为整个作业创建单元测试。但是我无法在
KeyedCoProcessFunction
中获得要触发的
onTimer()
回调

有人用过这个吗?它需要特殊配置吗

切换到事件时间工作正常,所以我想知道这是否在Flink MiniCluster中不起作用,或者我的实现是否有问题

我用Scala编写了一个简单的测试,看看是否可以让它工作

import org.apache.flink.api.common.typeinfo.TypeInformation
import org.apache.flink.runtime.testutils.MiniClusterResourceConfiguration
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.KeyedProcessFunction
import org.apache.flink.streaming.api.functions.source.{ParallelSourceFunction, SourceFunction}
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.test.streaming.runtime.util.TestListResultSink
import org.apache.flink.test.util.MiniClusterWithClientResource
import org.apache.flink.util.Collector
import org.scalatest.BeforeAndAfter
import org.scalatest.flatspec.AnyFlatSpec
import org.slf4j.LoggerFactory

class TimerTest extends AnyFlatSpec with BeforeAndAfter {

  private val SlotsPerTaskMgr = 1
  val flinkCluster = new MiniClusterWithClientResource(new MiniClusterResourceConfiguration.Builder()
    .setNumberSlotsPerTaskManager(SlotsPerTaskMgr)
    .setNumberTaskManagers(1)
    .build)

  before {
    flinkCluster.before()
  }

  after {
    flinkCluster.after()
  }

  "MiniCluster" should "trigger onTimer" in {
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    env.setParallelism(1)

    env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)

    implicit val longTypeInfo: TypeInformation[Long] = TypeInformation.of(classOf[Long])

    val sink = new TestListResultSink[Long]

    env.addSource(new MyLongSource(100))
      .keyBy(v => v)
      .process(new MyProccesor())
      .addSink(sink)

    env.execute()

    println("Received " + sink.getResult.size() + " output records.")
  }

}

class MyProccesor extends KeyedProcessFunction[Long, Long, Long] {

  private val log = LoggerFactory.getLogger(this.getClass)

  override def processElement(
                               value: Long,
                               ctx: KeyedProcessFunction[Long, Long, Long]#Context,
                               out: Collector[Long]): Unit = {
    log.info("Received {} at {}", value, ctx.timerService().currentProcessingTime())
    if (value % 10 == 0) {
      log.info("Scheduling processing timer for {}", ctx.timerService().currentProcessingTime() + 10)
      ctx.timerService().registerProcessingTimeTimer(ctx.timerService().currentProcessingTime() + 10)
    }
  }

  override def onTimer(
                        timestamp: Long,
                        ctx: KeyedProcessFunction[Long, Long, Long]#OnTimerContext,
                        out: Collector[Long]): Unit = {
    log.info("Received onTimer at {}", timestamp)
    out.collect(timestamp)
  }
}

class MyLongSource(n:Int) extends ParallelSourceFunction[Long] {
  @volatile private var stop = false

  override def run(ctx: SourceFunction.SourceContext[Long]): Unit = {
    for(i <- 1 to n) {
      if(stop) return;
      println("Sending " + i)
      ctx.collect(i)
    }

    Thread.sleep(1000)
  }

  override def cancel(): Unit = {
    stop = true
  }
}
import org.apache.flink.api.common.typeinfo.TypeInformation
导入org.apache.flink.runtime.testutils.MiniClusterResourceConfiguration
导入org.apache.flink.streaming.api.TimeCharacteristic
导入org.apache.flink.streaming.api.functions.KeyedProcessFunction
导入org.apache.flink.streaming.api.functions.source.{ParallelSourceFunction,SourceFunction}
导入org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
导入org.apache.flink.test.streaming.runtime.util.TestListResultink
导入org.apache.flink.test.util.MiniClusterWithClientResource
导入org.apache.flink.util.Collector
导入org.scalatest.before和after
导入org.scalatest.flatspec.AnyFlatSpec
导入org.slf4j.LoggerFactory
类TimerTest使用Before和After扩展AnyFlatSpec{
专用val SLOTSPTASKMGR=1
val flinkCluster=new MiniClusterWithClientResource(new MiniClusterResourceConfiguration.Builder())
.setNumberSlotsPerTaskManager(SlotsPerTaskMgr)
.SetNumberTaskManager(1)
(1.建造)
以前{
flinkCluster.before()
}
之后{
flinkCluster.after()
}
“微型集群”应在中“触发onTimer”{
val env=StreamExecutionEnvironment.getExecutionEnvironment
环境设置(1)
环境setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)
隐式val longTypeInfo:TypeInformation[Long]=TypeInformation.of(classOf[Long])
val sink=新的TestListResultSink[Long]
环境添加源(新MyLongSource(100))
.keyBy(v=>v)
.process(新的MyProccesor())
.addSink(sink)
env.execute()
println(“已接收”+sink.getResult.size()+“输出记录”)
}
}
MyProccesor类扩展了KeyedProcessFunction[Long,Long,Long]{
private val log=LoggerFactory.getLogger(this.getClass)
重写def processElement(
价值:长,
ctx:KeyedProcessFunction[Long,Long,Long]#上下文,
输出:收集器[长]:单位={
log.info(“在{}接收{}”,值,ctx.timerService().currentProcessingTime())
如果(值%10==0){
log.info(“调度{}的处理计时器”,ctx.timerService().currentProcessingTime()+10)
ctx.timerService().RegisterProcessingTimer(ctx.timerService().currentProcessingTime()+10)
}
}
覆盖def-onTimer(
时间戳:长,
ctx:KeyedProcessFunction[Long,Long,Long]#OnTimerContext,
输出:收集器[长]:单位={
info(“在{}处收到onTimer”,时间戳)
out.collect(时间戳)
}
}
类MyLongSource(n:Int)扩展了ParallelSourceFunction[Long]{
@volatile private var stop=false
覆盖def运行(ctx:SourceFunction.SourceContext[Long]):单位={

对于(i当Flink作业关闭时,任何挂起的处理时间计时器都将被忽略。它们从不触发

值得一提的是,Flink dev邮件列表上正在讨论提供一个选项来触发所有挂起的处理时间计时器。请参阅