在不重新启动整个JVM的情况下,将新代码推送到生产环服务器的最佳方法是什么?
目前我在生产中使用wrap-reload,但这对我来说并不适用,因为有时我想在ring开始使用新代码处理请求之前在repl中运行命令(例如进行数据库迁移).此外,各种博客和教程都说不要在生产中使用wrap-reload,尽管我不明白为什么不这样做.
我已经提出了以下解决方案,但我承认我并不深入了解引擎盖下发生了什么.我想知道我是否可以得到一个人的理智检查.这种技术看起来合理吗?
这个想法是有一个路径(/ admin/reload-clj)导致所有的clojure代码被重新加载.
(defonce ^:dynamic *jetty*)
(declare reload-clj)
(defn app [req]
...
(when (= (req :uri) "/admin/reload-clj") (reload-clj req))
...)
(defn start-jetty []
(let [j (run-jetty app {:port (http-port) :join? false :max-threads 16})]
(dosync (ref-set *jetty* j))
j))
(defn reload-clj [req]
(future
(log/info "Reloading clojure code...")
(require '(whrusrv admin main utils wdb) :reload-all)
(.stop @*jetty*)
(start-jetty)
(log/info "Clojure reload success!"))
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Reloading..."})
(defn -main [& args]
(start-jetty))
Run Code Online (Sandbox Code Playgroud)
您拥有的代码将起作用,但您应该知道:reload-all只加载命名空间和命名空间依赖项.它不会递归加载这些命名空间的依赖关系.
我应该补充说,以这种方式重新加载在生产系统中强烈不被推荐.
新部署的代码可能具有在系统重新启动之前不明显的错误(例如,它们依赖于仍然从正在运行的系统定义但其声明已被删除的var).系统将正常工作但重启后失败.
加载代码也可能有副作用,这可能会搞砸您的生产环境.虽然它避免了这些的好风格,但真正确保意外事件不会发生的唯一方法是重新启动JVM.
在JVM上执行零停机部署的最佳方法是使用负载平衡器进行滚动部署.
| 归档时间: |
|
| 查看次数: |
1185 次 |
| 最近记录: |