使用Slick收听PostgreSQL NOTIFY事件

gla*_*kou 6 postgresql scala playframework slick slick-3.0

我可以使用Slick/Play Framework(Scala)来收听PostgreSQL NOTIFY语句吗?

我想做类似的事情:

http://bjorngylling.com/2011-04-13/postgres-listen-notify-with-node-js.html

Jef*_*ung 7

我不认为Slick支持PostgreSQLNOTIFY,但postgresql-async库支持.可以使用后者创建Akka Streams Source并将其合并到Play端点中,以将数据库通知流式传输到客户端:

package controllers

import javax.inject.{Inject, Singleton}

import akka.actor._
import akka.stream._
import akka.stream.scaladsl._

import com.github.mauricio.async.db.postgresql.PostgreSQLConnection
import com.github.mauricio.async.db.postgresql.util.URLParser
import com.github.mauricio.async.db.util.ExecutorServiceUtils.CachedExecutionContext

import play.api.Logger
import play.api.http.ContentTypes
import play.api.libs.EventSource
import play.api.mvc._

import scala.concurrent.duration._
import scala.concurrent.Await

@Singleton
class DbNotificationController @Inject()(cc: ControllerComponents,
                                         materializer: Materializer)
  extends AbstractController(cc) {

  implicit val mat = materializer

  val configuration = URLParser.parse("jdbc:postgresql://localhost:5233/my_db?user=dbuser&password=pwd")
  val connection = new PostgreSQLConnection(configuration)
  Await.result(connection.connect, 5 seconds)

  val (actor, dbSource) =
    Source.actorRef[String](Int.MaxValue, OverflowStrategy.dropNew)
          .toMat(BroadcastHub.sink[String])(Keep.both)
          .run()

  connection.sendQuery("LISTEN my_channel")
  connection.registerNotifyListener { message =>
    val msg = message.payload
    Logger.debug(s"Sending the payload: $msg")
    actor ! msg
  }

  def index() = Action {
    Ok(views.html.scaladbnotification())
  }

  def streamDb() = Action {
    Ok.chunked(dbSource via EventSource.flow).as(ContentTypes.EVENT_STREAM)
  }
}
Run Code Online (Sandbox Code Playgroud)

在上述控制器中,当监听器从数据库接收通知时,通知中的有效载荷(a String)被记录并发送给演员.发送到此actor的消息Source将提供streamDb端点中使用的消息.在将有效负载消息发送到客户端之前,它们将转换为Play的EventSource类.


我改编DbNotificationControllerPlay流媒体示例应用程序,您可以使用它来进行实验.如果您愿意这样做,显然您需要集成DbNotificationController到该项目中:

  1. 添加"com.github.mauricio" %% "postgresql-async" % "0.2.21"build.sbt.
  2. 根据需要设置PostgreSQL,包括NOTIFY,并根据您的配置调整控制器中的数据库URL.
  3. 复制并粘贴DbNotificationController/app/controllers/.
  4. 将以下文件(调用它scaladbnotification.scala.html)复制到app/views/:
@main {

    <h1>Server Sent Event from DB</h1>

    <h1 id="db"></h1>

    <p>
        DB events are pushed from the Server using a Server Sent Event connection.
    </p>

    <script type="text/javascript" charset="utf-8">
        if (!!window.EventSource) {
            var stringSource = new EventSource("@routes.DbNotificationController.streamDb()");
            stringSource.addEventListener('message', function(e) {
                $('#db').html(e.data.replace(/(\d)/g, '<span>$1</span>'))
            });
        } else {
            $("#db").html("Sorry. This browser doesn't seem to support Server sent event. Check <a href='http://html5test.com/compare/feature/communication-eventSource.html'>html5test</a> for browser compatibility."); 
        }
    </script>    
}
Run Code Online (Sandbox Code Playgroud)

  1. /conf/routes文件中,添加以下行:
    GET /scala/dbNotification           controllers.DbNotificationController.index()
    GET /scala/dbNotification/liveDb    controllers.DbNotificationController.streamDb()
  1. 启动应用程序sbt run并在浏览器中导航到以下URL:

    HTTP://本地主机:9000 /斯卡拉/ dbNotification