实现“实时”流来驱动Akka 2.4持久性查询

时间:2016-01-05 22:24:28

标签: scala akka akka-persistence

我一直在研究实验性的Akka Persistence Query模块,并且非常有兴趣为我的应用程序实现自定义读取日志。该文档描述了两种主要的查询形式,一种返回日志的当前状态(例如CurrentPersistenceIdsQuery),另一种返回可订阅的流,当事件通过写入端提交给日志时发出事件。应用程序(例如AllPersistenceIdsQuery

对于我的设计应用程序,我使用Postgres和Slick 3.1.1来驱动这些查询的内容。我可以通过以下方式成功地传输数据库查询结果:

override def allPersistenceIds = {
  val db = Database.forConfig("postgres")
  val metadata = TableQuery[Metadata]

  val query = for (m <- metadata) yield m.persistenceId
  Source.fromPublisher(db.stream(query.result))
}

但是,只要基础Slick DB操作完成,就会将流信号通知为完成。这似乎不能满足能够发出新事件的永久开放流的要求。

我的问题是:

  • 有没有办法纯粹使用Akka Streams DSL?也就是说,我可以发送一个无法关闭的流程吗?
  • 我已经对LevelDB读取日志的工作方式进行了一些探索,并且似乎通过让读取日志订阅写日志来处理新事件。这似乎是合理的,但我必须要问 - 一般来说,是否有推荐的方法来处理这个要求?
  • 我想到的另一种方法是轮询(例如,定期让我的读取日志查询数据库并检查新事件/ ID)。有经验的人会比我能提供一些建议吗?

谢谢!

2 个答案:

答案 0 :(得分:4)

这不像这一行代码那么简单,但你已经是正确的轨道了。

为了实现“无限”流,您需要多次查询 - 即实现轮询,除非底层数据库允许无限查询(这里不是AFAICS)。

轮询需要跟踪“偏移量”,因此如果您通过某个标记进行查询,并发出另一个轮询,则需要从“最后发出的元素”开始(第二个)查询,并且不是表的开头了。所以你需要某个地方,很可能是一个保持这种偏移的人。

Query Side LevelDB插件不是其他实现的最佳角色模型,因为它假设了很多关于底层日志及其工作原理。此外,LevelDB并不适用于Akka Persistence的制作 - 它是我们发行的期刊,以便拥有一个可以开箱即用的持久性日记(无需启动Cassandra等)。

如果您正在寻找灵感,MongoDB插件实际上应该是一个非常好的源,因为它们具有与SQL存储非常相似的限制。我不确定是否有任何SQL日志当前实现了Query端。

答案 1 :(得分:0)

可以使用Postgres replication API来获取“无限”的数据库事件流。 Postgres JDBC驱动程序从版本42.0.0开始支持它,请参阅相关的pull request。 但是,它不是真正的流,而是来自数据库WAL的缓冲同步读取器。

PGReplicationStream stream =
    pgConnection
        .replicationStream()
        .logical()
        .withSlotName("test_decoding")
        .withSlotOption("include-xids", false)
        .withSlotOption("skip-empty-xacts", true)
        .start();
while (true) {
  ByteBuffer buffer = stream.read();
  //process logical changes
}

对于这个读者,在alpakka project中有一个Akka Streams适配器(Source)会很好。