使用Akka Streams 2.4.2和Slick 3.0

时间:2016-02-19 16:01:30

标签: scala akka-stream slick-3.0

尝试新建的Akka Streams。它似乎工作除了一件小事 - 没有输出。

我有以下表格定义:

case class my_stream(id: Int, value: String)

class Streams(tag: Tag) extends Table[my_stream](tag, "my_stream") {
  def id = column[Int]("id")
  def value = column[String]("value")
  def * = (id, value) <> (my_stream.tupled, my_stream.unapply)
}

我正在尝试将表的内容输出到stdout,如下所示:

def main(args: Array[String]) : Unit = {
  implicit val system = ActorSystem("Subscriber")
  implicit val materializer = ActorMaterializer()

  val strm = TableQuery[Streams]
  val db = Database.forConfig("pg-postgres")

  try{
    var src = Source.fromPublisher(db.stream(strm.result))
    src.runForeach(r => println(s"${r.id},${r.value}"))(materializer)
  } finally {
    system.shutdown
    db.close
  }
}

我已通过配置调试日志记录验证了正在运行查询。但是,我得到的只是:

08:59:24.099 [main] INFO  com.zaxxer.hikari.HikariDataSource - pg-postgres - is starting.
08:59:24.428 [main] INFO  com.zaxxer.hikari.pool.HikariPool - pg-postgres - is closing down.

3 个答案:

答案 0 :(得分:3)

原因是Akka Streams是异步的, <plugin> <groupId>com.google.appengine</groupId> <artifactId>appengine-maven-plugin</artifactId> <version>1.9.32</version> <configuration> <enableJarClasses>false</enableJarClasses> </configuration> <executions> <execution> <goals> <goal>endpoints_get_discovery_doc</goal> </goals> </execution> </executions> </plugin> 返回一个Future,它将在流完成后完成,但Future未被处理,因此runForeach和{{1}立即执行,而不是在流完成后执行。

答案 1 :(得分:1)

为了防止任何人在MySQL中搜索同样的问题,请考虑您应该“手动”启用驱动程序流支持:

def enableStream(statement: java.sql.Statement): Unit = {
  statement match {
    case s: com.mysql.jdbc.StatementImpl => s.enableStreamingResults()
    case _ =>
  }
}

val publisher = sourceDb.stream(query.result.withStatementParameters(statementInit = enableStream))

来源:http://www.slideshare.net/kazukinegoro5/akka-streams-100-scalamatsuri

答案 2 :(得分:0)

使用@ViktorKlang答案结束,然后用Await.result包裹运行。我还找到了一个替代答案in the docs,它演示了如何使用反应流发布者和订阅者接口:

stream方法返回DatabasePublisher[T]Source.fromPublisher返回Source[T, NotUsed]。这意味着您必须附加订阅者而不是使用runForEach - 根据release notes NotUsed替换Unit。这意味着什么都没有传递给Sink

由于Slick实现了反应流接口而不是Akka Stream接口,因此您需要使用fromPublisherfromSubscriber集成点。这意味着您需要实现org.reactivestreams.Subscriber[T]接口。

这是一个快速而简洁的Subscriber[T]实施,只需拨打println

class MyStreamWriter extends org.reactivestreams.Subscriber[my_stream] {
  private var sub : Option[Subscription] = None;

  override def onNext(t: my_stream): Unit = {
    println(t.value)
    if(sub.nonEmpty) sub.head.request(1)
  }

  override def onError(throwable: Throwable): Unit = {
    println(throwable.getMessage)
  }

  override def onSubscribe(subscription: Subscription): Unit = {
    sub = Some(subscription)
    sub.head.request(1)
  }

  override def onComplete(): Unit = {
    println("ALL DONE!")
  }
}

您需要确保在Subscription.request(Long)中调用onSubscribe方法,然后在onNext中调用数据,否则不会发送任何内容,或者您​​无法获得全部内容一组结果。

以下是你如何使用它:

def main(args: Array[String]) : Unit = {
  implicit val system = ActorSystem("Subscriber")
  implicit val materializer = ActorMaterializer()

  val strm = TableQuery[Streams]
  val db = Database.forConfig("pg-postgres")

  try{
    val src = Source.fromPublisher(db.stream(strm.result))
    val flow = src.to(Sink.fromSubscriber(new MyStreamWriter()))
    flow.run()
  } finally {
    system.shutdown
    db.close
  }
}

我仍然想弄清楚这一点,所以我欢迎任何反馈。谢谢!