使用条件语句发送给不同的接收者角色

时间:2015-11-12 20:55:23

标签: scala akka

我是akka的新手,可以用一些帮助来解决这个问题,如果我用错误的名字打电话,请原谅我。我有一个json文档需要根据特定字段是否为真来转到两个接收器之一。我已经能够使用以下方式向各个单一消费者发布:

[{"item":"foo","category_id":1},{"item":"bar","category_id":2},[3]]

我尝试插入这样的条件语句:

Source(publisher).map{cmd =>
  println("****************** Pick up message"+cmd)
  val cmdAst = cmd.toString.parseJson
  cmdAst.convertTo[FormAdded]
}.runWith(Sink.actorSubscriber(ProcessorActor.props))

所有内容都编译并运行没有错误,但是当提交表单时,它永远不会被提取并且只是超时。

我还试图通过以下方式直接将用户吸收到相同的结果:

var actorSubscriber = ProcessorActor.props

Source(publisher).map { cmd =>
  println("****************** Pick up message" + cmd)
  val cmdAst = cmd.toString.parseJson
  cmdAst.convertTo[FormAdded]
    if (cmdAst.convertTo[FormAdded].toLocation.toString().equalsIgnoreCase("Main")) {
      actorSubscriber = EventActor.props
    } else actorSubscriber = ProcessorActor.props
}.runWith(Sink.actorSubscriber(actorSubscriber))

谢谢

2 个答案:

答案 0 :(得分:3)

这可以使用Graph使用Broadcast和两个不同的接收器来完成。下面是一个使用Source整数并将它们分成两个不同的接收器的示例,一个用于均衡,一个用于赔率。

import scala.concurrent.duration._
import akka.stream.scaladsl.{Source, Sink, Flow, FlowGraph, Broadcast, Merge}
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer

object TwoSinks extends App {

  implicit val actorSystem = ActorSystem()
  implicit val materializer = ActorMaterializer()

  FlowGraph.closed() { implicit builder: FlowGraph.Builder[Unit] =>
    import FlowGraph.Implicits._

    val source = Source(1 to 10)

    //beam splitter
    val bcast = builder.add(Broadcast[Int](2))

    def isEven(i : Int) = i % 2 == 0

    val evenFilter = Flow[Int].filter(isEven)
    val oddFilter  = Flow[Int].filter(!isEven(_))

    val evenSink = Sink.foreach[Int](i => println(s"evenSink received : $i"))    
    val oddSink  = Sink.foreach[Int](i => println(s" oddSink received : $i"))

    source ~> bcast ~> evenFilter ~> evenSink
              bcast ~> oddFilter  ~> oddSink
  }.run()

  import actorSystem.dispatcher
  actorSystem.scheduler.scheduleOnce(10 seconds){actorSystem.shutdown()}
}//end object TwoSinks

您可以轻松扩展此示例以使用在您的接收器中使用Actors而不是println的Sink.actorSubscriber。使用您的特定代码:

FlowGraph.closed() {implicit builder: FlowGraph.Builder[Unit] =>
  import FlowGraph.Implicits._

  def pickupMsg(cmd : String) = 
    {println(s"****************** Pick up message: $cmd") ; cmd}

  //I don't know the type of cmdAst so I'm using "CmdAstType"
  type CmdAstType = ???

  def convert(cmd : String) : CmdAstType = {
    val cmdAst = cmd.toString.parseJson
    cmdAst.convertTo[FormAdded]
    cmdAst
  }//end def convert

  val source = Source(publisher).map(pickupMsg).map(convert)

  def isEvent(cmdAst : CmdAstType) : Boolean = cmdAst.convertTo[FormAdded]
                                                     .toLocation 
                                                     .toString()
                                                     .equalsIgnoreCase("Main")

  val eventFilter     = Flow[CmdAstType].filter(isEvent)
  val processorFilter = Flow[CmdAstType].filter(!isEvent(_))

  val eventSink     = Sink.actorSubscriber[CmdAstType](EventActor.props)
  val processorSink = Sink.actorSubscriber[CmdAstType](ProcessorActor.props)

  val bcast = builder.add(Broadcast[CmdAstType](2))

  source ~> bcast ~> eventFilter     ~> eventSink
            bcast ~> processorFilter ~> processorSink

}//end FlowGraph.closed()

答案 1 :(得分:2)

你不能让Sink依赖于元素:流程已经存在并且在它运行之前包含固定的SourceSink并且开始从源获取元素(有{ {3}}但他们都没有做你想要的事情。

可以做的是有一个Sink,它会根据元素将收到的元素转发给不同的actor。例如。您可以撰写DispatchActor来查看收到的邮件,并将其发送到EventActorProcessorActor,并将其与Sink.actorSubscriber(DispatchActor.props)一起使用。