9

JVM全体を再起動せずに新しいコードをプロダクションリングサーバーにプッシュする最良の方法は何ですか?

現在、本番環境で wrap-reload を使用していますが、リングが新しいコードでリクエストの処理を開始する前に、repl でコマンドを実行したい場合があるため (データベースの移行など)、これはうまくいきません。また、さまざまなブログやチュートリアルで、本番環境で wrap-reload を使用しないようにと書かれていますが、その理由はわかりません。

私は次の解決策を思いつきましたが、内部で何が起こっているのかを深く理解していないことを告白します. 誰かが健全性チェックを受けられるかどうか疑問に思っていました。このテクニックは合理的ですか?

アイデアは、すべての clojure コードをリロードさせるパス (/admin/reload-clj) を持つことです。

(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))
4

2 に答える 2

7

:reload-allあなたが持っているコードは機能しますが、名前空間のみをロードし、名前空間の依存関係に注意する必要があります。これらの名前空間の依存関係を再帰的にロードすることはありません。

この方法でのリロードは、実稼働システムでは強く推奨されないことを付け加えておきます。

新しくデプロイされたコードには、システムを再起動するまで明らかにならないエラーがある場合があります (たとえば、実行中のシステムからまだ定義されているが、宣言が削除された var に依存しています)。システムは正常に動作しますが、再起動時に失敗します。

コードのロードには、本番環境を台無しにする可能性のある副作用もあります。これらを回避するのは良いスタイルですが、予期しないことが起こらないことを本当に確実にする唯一の方法は、JVM を再起動することです。

JVM でゼロ ダウンタイム デプロイを行う最善の方法は、ロード バランサーを使用したローリング デプロイです。

于 2012-09-07T16:05:36.563 に答える
2

私は前職で Common Lisp のイントラネット Web サービスを持っていたので、それが本番環境に該当するかどうかはわかりません。また、CLに参加していることは、リング固有でもClojure固有でもありません。それでも、コードのリロードには便利です。

私がしたことは、実稼働の Lisp インスタンスでスワンク サーバー (スライムの一部) を起動し、デスクトップからリモートで接続することです。そうすれば、新しいコードを書いたり、コードを書き直したり、デバッグしたり、リロードしたりできます。明らかに、実際の運用システムでは特に注意が必要です。

clojure でも同様のことができます。nrepl のように、swank に代わるものもあります。

セキュリティも考慮して、ローカル接続のみを許可するか、自分に合ったものを許可する必要があります。

于 2012-04-03T11:41:39.343 に答える