如何将MongoDB Scala异步驱动程序与Akka Streams集成?

时间:2016-01-12 16:48:55

标签: mongodb scala akka-stream

我将旧的Casbah Mongo驱动程序迁移到新的异步Scala驱动程序,我试图在Akka流中使用它,并且流卡住了。

我有一个定义了createLogic()的GraphStage。代码如下。这对Casbah来说很好用,我希望新mongo驱动程序的异步性能非常合适,但在这里会发生什么......

如果我通过此代码传输2条记录,则第一条记录会流过并触发下一步。请参阅下面的输出('此处发送'确认通过)。第二条记录似乎在BlacklistFilter中执行了正确的步骤,但Akka从未流向SEND步骤。

为什么不能使用新驱动程序的任何想法?

object BlacklistFilter {
  type FilterShape = FanOutShape2[QM[RenderedExpression], QM[RenderedExpression], QM[Unit]]
}
import BlacklistFilter._
case class BlacklistFilter(facilities: Facilities, helloConfig: HelloConfig)(implicit asys: ActorSystem) extends GraphStage[FilterShape] {
  val outPass: Outlet[QM[RenderedExpression]] = Outlet("Pass")
  val outFail: Outlet[QM[Unit]] = Outlet("Fail")
  val reIn: Inlet[QM[RenderedExpression]] = Inlet("Command")

  override val shape: FilterShape = new FanOutShape2(reIn, outPass, outFail)

  override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) {
    override def preStart(): Unit = pull(reIn)

    setHandler(reIn, new InHandler {
      override def onPush(): Unit = {
        val cmd = grab(reIn)
        val re: RenderedExpression = cmd.body
        val check = re.recipient.contacts(re.media).toString

        // NEW NON-BLOCKING CODE 
        //-------------------------------------
        facilities.withMongo(helloConfig.msgDB, helloConfig.blacklistColl) { coll =>
          var found: Option[Document] = None
          coll.find(Document("_id" -> check)).first().subscribe(
            (doc: Document) => {
              found = Some(doc)
              println("BLACKLIST FAIL! " + check)
              emit(outFail, cmd)
              // no pull() here as this happens on complete below
            },
            (e: Throwable) => {
              // Log something here!
              emit(outFail, cmd)
              pull(reIn)
            },
            () => {
              if (found.isEmpty) {
                println("BLACKLIST OK. " + check)
                emit(outPass, cmd)
              }
              pull(reIn)
              println("Pulled reIn...")
            }
          )
        }

        // OLD BLOCKING CASBAH CODE THAT WORKED
        //-------------------------------------
        // await(facilities.mongoAccess().mongo(helloConfig.msgDB, helloConfig.blacklistColl)(_.findOne(MongoDBObject("_id" -> check)))) match {
        //   case Some(_) => emit(outFail, cmd)
        //   case None    => emit(outPass, cmd)
        // }
        // pull(reIn)
      }
      override def onUpstreamFinish(): Unit = {} // necessary for some reason!
    })
    setHandler(outPass, eagerTerminateOutput)
    setHandler(outFail, eagerTerminateOutput)
  }
}

输出:

BLACKLIST OK. jsmith@yahoo.com
Pulled reIn...
HERE IN SEND (TemplateRenderedExpression)!!!
ACK!
BLACKLIST OK. 919-919-9119
Pulled reIn...

您可以从输出中看到第一条记录很好地流向了SEND / ACK步骤。第二条记录打印出BLACKLIST消息,意味着它发出outPass然后调用了reIn ...但是后来没有任何事情发生。

任何人都知道为什么这种方法在Akka Streams中的工作方式与Casbah版本的工作方式不同(代码显示已注释掉)?

(我可以将Mongo调用转换为Future并等待它,这应该像旧代码一样工作,但这有点打败了异步的全部意义!)

1 个答案:

答案 0 :(得分:1)

那么......"没关系"! : - )

上面的代码似乎就像应该有效一样。然后我注意到Akka的家伙刚刚发布了新版本(2.0.1)。我不确定是什么调整,但不管它是什么,上面的代码现在可以起作用,因为我希望不需要修改。

留下这篇文章以防万一有人遇到类似的问题。