gpt4 book ai didi

clojure - 如何在Clojure中使用Stuart Sierra的组件库

转载 作者:行者123 更新时间:2023-12-02 03:31:09 29 4
gpt4 key购买 nike

我正在努力思考如何使用 Stuart Sierra's component library在 Clojure 应用程序中。从观看他的Youtube video ,我想我已经很好地理解了导致他创建这个库的问题;然而,我正在努力弄清楚如何在一个新的、相当复杂的项目中实际使用它。

我意识到这听起来很模糊,但感觉好像我缺少一些关键概念,一旦我理解了它,我就会很好地掌握如何使用组件。换句话说,Stuart 的文档和视频相当详细地介绍了组件的内容和原因,但我忽略了如何使用。

是否有任何详细的教程/演练:

  • 为什么要在一个不平凡的 Clojure 应用中使用组件
  • 一种如何分解重要 Clojure 应用程序中的功能的方法,以便可以以合理的最佳方式实现组件。当你所拥有的只是例如一个数据库、一个应用程序服务器和一个 Web 服务器层,但我很难掌握如何将它用于一个具有许多不同层的系统,这些层都需要协同工作
  • 进行开发/测试/故障转移等的方法。在使用组件构建的重要 Clojure 应用程序中

提前致谢

最佳答案

简而言之,Component是一个专门的DI框架。它可以在给定两个映射的情况下设置注入(inject)系统:系统映射和依赖关系映射。

让我们看一个虚构的网络应用程序(免责声明,我在表单中输入了此应用程序,但没有实际运行它):

(ns myapp.system
(:require [com.stuartsierra.component :as component]
;; we'll talk about myapp.components later
[myapp.components :as app-components]))

(defn system-map [config] ;; it's conventional to have a config map, but it's optional
(component/system-map
;; construct all components + static config
{:db (app-components/map->Db (:db config))
:handler (app-components/map->AppHandler (:handler config))
:server (app-components/map->Server (:web-server config))}))

(defn dependency-map
;; list inter-dependencies in either:
;; {:key [:dependency1 :dependency2]} form or
;; {:key {:name-arg1 :dependency1
;; :name-arg2 :dependency2}} form
{:handler [:db]
:server {:app :handler})

;; calling this creates our system
(def create-system [& [config]]
(component/system-using
(system-map (or config {})
(dependency-map)))

这允许我们在需要时调用(create-system)来创建整个应用程序的新实例。

使用(component/startcreated-system),我们可以运行系统提供的服务。在本例中,网络服务器正在监听端口和打开的数据库连接。

最后,我们可以使用 (component/stopcreated-system) 来停止它,以停止系统运行(例如 - 停止 Web 服务器,断开与数据库的连接)。

现在让我们看看我们应用程序的 components.clj:

(ns myapp.components
(:require [com.stuartsierra.component :as component]
;; lots of app requires would go here
;; I'm generalizing app-specific code to
;; this namespace
[myapp.stuff :as app]))

(defrecord Db [host port]
component/Lifecycle
(start [c]
(let [conn (app/db-connect host port)]
(app/db-migrate conn)
(assoc c :connection conn)))
(stop [c]
(when-let [conn (:connection c)]
(app/db-disconnect conn))
(dissoc c :connection)))

(defrecord AppHandler [db cookie-config]
component/Lifecycle
(start [c]
(assoc c :handler (app/create-handler cookie-config db)))
(stop [c] c))

;; you should probably use the jetty-component instead
;; https://github.com/weavejester/ring-jetty-component
(defrecord Server [app host port]
component/Lifecycle
(start [c]
(assoc c :server (app/create-and-start-jetty-server
{:app (:handler app)
:host host
:port port})))
(stop [c]
(when-let [server (:server c)]
(app/stop-jetty-server server)
(dissoc c :server)))

那么我们刚刚做了什么?我们给自己准备了一个可重新加载的系统。我认为一些使用 figwheel 的 clojurescript 开发人员开始看到相似之处。

这意味着我们可以在重新加载代码后轻松地重新启动系统。转到user.clj!

(ns user
(:require [myapp.system :as system]
[com.stuartsierra.component :as component]
[clojure.tools.namespace.repl :refer (refresh refresh-all)]
;; dev-system.clj only contains: (def the-system)
[dev-system :refer [the-system]])

(def system-config
{:web-server {:port 3000
:host "localhost"}
:db {:host 3456
:host "localhost"}
:handler {cookie-config {}}}

(def the-system nil)

(defn init []
(alter-var-root #'the-system
(constantly system/create-system system-config)))

(defn start []
(alter-var-root #'the-system component/start))

(defn stop []
(alter-var-root #'the-system
#(when % (component/stop %))))

(defn go []
(init)
(start))

(defn reset []
(stop)
(refresh :after 'user/go))

要运行系统,我们可以在 repl 中键入以下内容:

(user)> (reset)

这将重新加载我们的代码,并重新启动整个系统。如果正在运行,它将关闭正在运行的现有系统。

我们还有其他好处:

  • 端到端测试很简单,只需编辑配置或替换组件以指向进程内服务(我用它来指向进程内 kafka 服务器进行测试)。
  • 理论上,您可以为同一个 JVM 多次生成应用程序(实际上并不像第一点那么实用)。
  • 当您更改代码并且必须重新启动服务器时,无需重新启动 REPL
  • 与环重新加载不同,我们可以采用统一的方式重新启动应用程序,无论其用途如何:后台工作线程、微服务或机器学习系统都可以采用相同的方式构建。

值得注意的是,由于一切都在进程中,组件不处理与故障转移、分布式系统或错误代码相关的任何内容;)

组件可以帮助您在服务器内管理大量“资源”(也称为有状态对象):

  • 与服务(队列、数据库等)的连接
  • 时间流逝(调度程序、cron 等)
  • 日志记录(应用日志记录、异常日志记录、指标等)
  • 文件 IO(blob 存储、本地文件系统等)
  • 传入的客户端连接(网络、套接字等)
  • 操作系统资源(设备、线程池等)

如果您只有一个 Web 服务器 + 数据库,组件可能看起来有点矫枉过正。但如今很少有网络应用程序能做到这一点。

旁注:the-system 移动到另一个命名空间可以减少开发时刷新 the-system var 的可能性(例如 - 调用刷新而不是重置)。

关于clojure - 如何在Clojure中使用Stuart Sierra的组件库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29070883/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com