首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用后现代包实现Common Lisp中的表更改时的客户端通知

使用后现代包实现Common Lisp中的表更改时的客户端通知
EN

Stack Overflow用户
提问于 2020-07-27 12:10:46
回答 1查看 209关注 0票数 3

在谷歌搜索和寻找示例很长一段时间后,我找不到任何迹象表明,当数据库表发生变化时,是否可以在客户端应用程序中获得通知“回调”。

postgresql C库支持该特性(至少在某种程度上),因此数据库本身似乎支持此用例。

代码语言:javascript
复制
CREATE TABLE IF NOT EXISTS disco (
instance TEXT NOT NULL,
service TEXT NOT NULL,
attributes TEXT[] DEFAULT '{}',
endpoints TEXT[],
CONSTRAINT service_instance PRIMARY KEY(instance,service));

基于上面给出的表,我使用postmodern PostgreSQL包创建了一个小的Lisp包,它允许广告一些服务(它是一个玩具服务发现,由数据库支持)。

当然,除了广告之外,应用程序还需要等待/搜索活动服务。由于轮询显然不是可行的方式,因此需要某种形式的通知。在can级别,应用程序可以使用select()等待套接字,连接到数据库和PQNotify()或类似的东西。

我的问题是,如果postmodern也支持这个用例,我正在寻找一个例子。

这是我到目前为止所做的LISP包。

代码语言:javascript
复制
(ql:quickload :postmodern)
(defpackage :disco
  (:use :common-lisp :postmodern)
  (:export
   :connect-toplevel
   :ensure-disco-table
   :advertise
   :stop-advertise
   :advertised)
  (:shadow :connect-toplevel))
(in-package :disco)
(defun ensure-disco-table ()
  (postmodern:query "CREATE TABLE IF NOT EXISTS disco (
instance TEXT NOT NULL,
service TEXT NOT NULL,
attributes TEXT[] DEFAULT '{}',
endpoints TEXT[],
CONSTRAINT service_instance PRIMARY KEY(instance,service));"))
(defun connect-toplevel ()
  (progn
    (postmodern:connect-toplevel "postgres" "postgres" "password" "localhost")
    (ensure-disco-table)))
(defun advertise (instance service endpoints &optional attributes)
  (let ((attribs (if attributes attributes #())))
      (postmodern:query (:insert-into 'disco :set 'instance instance
                                      'service service
                                      'attributes attribs
                                      'endpoints endpoints))))

(defun stop-advertise (instance service)
  (postmodern:query (:delete-from 'disco
                                         :where (:and
                                                 (:= 'instance instance)
                                                 (:= 'service service)))))

(defun advertised (instance service endpoints handler &optional attributes)
  (if (advertise instance service endpoints attributes)
      (progn
        (funcall handler)
        (stop-advertise instance service)
        T)
      nil))

对于搜索部分,我想要一个类似如下的函数:

代码语言:javascript
复制
(defun with-services (filters continuation)
  ; ...
)

其中filters允许查找例如服务名称和属性(真的与问题无关),一旦所有需要的服务都可用,将使用相关服务的行列表调用continuation函数。

with-services函数可以阻塞,直到需要的每个服务都存在,也可以异步执行。

想法,如果不扩展后现代套餐,这是可能的吗?它会是什么样子呢?

更新

因为我找不到文档,所以我深入到了源代码级别,并在文件protocol.lisp中找到了通知是如何处理的:

代码语言:javascript
复制
(defun get-notification (socket)
  "Read an asynchronous notification message from the socket and
signal a condition for it."
  (let ((pid (read-int4 socket))
        (channel (read-str socket))
        (payload (read-str socket)))
    (warn 'postgresql-notification
          :pid pid
          :channel channel
          :payload payload
          :format-control "Asynchronous notification ~S~@[ (payload: ~S)~]
                           received from ~ server process with PID ~D."
          :format-arguments (list channel payload pid))))

因此,在我还没有受过良好训练的LISP眼睛看来,通知似乎以某种方式映射到了某种异常。在其他语言中,这通常是一种代码气味。这是不是意味着,通知处理是隐藏的非功能,或者这是在Common Lisp中惯用的方式?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-29 16:25:52

常见的Lisp条件不是例外,因为发出信号并不会展开堆栈。这是Common Lisp条件系统的自然用法,C++/Java/Python等流行的纯抛出异常系统无法实现这一点。

函数WARN发出条件信号,允许匹配条件类型POSTGRESQL-NOTIFICATION的条件处理程序触发,然后调用MUFFLE-WARNING重新启动以继续执行。这里使用WARNMUFFLE-WARNING未处理警告的情况下将警告消息打印到标准输出。

让我们考虑以下代码:

代码语言:javascript
复制
(labels ((handle-notification-p (condition)
           (let ((pid (postgresql-notification-pid condition))
                 (channel (postgresql-notification-channel condition))
                 (payload (postgresql-notification-payload condition)))
             ...)) ;; return true if we want to handle this notification
         (handle-notification (condition)
           (when (handle-notification-p condition)
             ... ;; perform actions to handle the notifications
             (invoke-restart 'muffle-warning condition))))
  (handler-bind ((postgresql-notification #'handle-notification))
    ...)) ;; application logic goes here

这段代码建立一个处理通知条件的处理程序。它有三个地方需要填写。

当条件应该由这个处理程序处理时,第一个函数应该返回true。第二个问题-在将控制返回到警告站点之前,应该执行哪些步骤来处理这种情况。第三个应该包含应用程序逻辑,其中包含一些处理与Postgres通信的服务器代码。

所有这些都是在不展开堆栈的情况下发生的(除非其他条件处理程序显式地在其他地方执行非本地退出)。如果处理了通知,将从WARN站点继续执行,如果未处理,将继续将警告打印到标准输出。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63108594

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档