clojure:类似单例数据连接的最佳方法

我正在创建与elasticsearch的连接(但是替换您喜欢的任何其他数据源),它将基于运行时的环境或配置文件参数.它看起来像这样:

(defn create-conn
  "Connect to the given uri. This is a persistent conn managed by clj-http (apache)."
  ([uri]
   ( ;;; create a persistent connection using clj-http / elastic
   ...)
  ([]
   (create-conn (or (System/getenv "ES_URL")
                    (cfg/get-url-from-config-file)
                    "http://localhost:9200"))))

因为连接在服务器的生命周期内不会改变,所以我只需要运行一次这个函数并缓存结果.有几种方法可以做到这一点:

1 – 记住它 – 虽然这有效,但它感觉不是正确的方法,因为我只是缓存一件事
2 – 使用像Component或mount这样的状态管理器;因为我不是真正管理国家,只是设置和遗忘,而只是将它用于这一件事,感觉有点矫枉过正.例如,以下如何优于下面的#3?

; mount version -- good, but how is this better than #3 below?
(defstate conn :start (getconn))
(mount/start #'elastic/conn)   ;; somewhere else, must start mount

3 – def it.即使运行create-conn实际上并没有执行任何网络活动,我宁愿不在文件加载时运行它,如果我只是对它进行常规def会发生什么,所以我必须做类似的事情以下…注意getconn函数是为了方便,所以我不必直接deref conn:

(def conn (delay (create-conn)))
(defn getconn [] @conn)

4 – 使用一个原子 – 直截了当,但这不是一个需要改变的var,它引入了一个不需要的状态:

(def conn (atom nil))
(def getconn []
  (if-not @conn (reset! conn (create-conn)))
  @conn)

5 – [在此插入您的想法]

在上面,我更喜欢3,因为它使用不可变数据,即使延迟有点笨重.您的偏好是什么,无论是来自上面的列表,还是您自己的解决方案?

最佳答案
Mount
component正是为此而建造的 – 控制状态大多是固定的(有时需要更新连接). Mount是两个库中最简单的一个,允许您定义连接一次,并在需要的地方“需要”它.

点赞