Я изучаю clojure и столкнулся с трудностями при попытке реорганизовать мое веб-приложение, чтобы сделать его более функциональным и менее зависимым от глобального состояния.
То, как вы делаете простой сервер с автоматической перезагрузкой с ring
, выглядит следующим образом:
(defn handler [req]
{:status 200
:body "<h1>Hello World</h1>"
:headers {}})
(defn -main []
(jetty/run-jetty (wrap-reload #'handler)
{:port 12345}))
(источник: https://practicalli.github.io/clojure-webapps/middleware-in-ring/wrap-reload.html)
Итак, handler
- это глобальная функция. Это дано как var
ссылка на wrap-reload
. При каждом запросе wrap-reload
будет перезагружать все пространство имен, а затем повторно разрешать handler
ссылку на потенциально другую функцию. Или, по крайней мере, это мое понимание.
Это все хорошо в этом простом примере. Проблема начинается, когда я заменяю этот hello world обработчик своим фактическим обработчиком, к которому привязаны все виды состояний (например, соединение с базой данных). Это состояние инициализируется один раз внутри -main
, а затем вводится в стек маршрутизации. Примерно так:
(defn init-state [args dev]
(let
[db (nth args 1 "jdbc:postgresql://localhost/mydb")
routes (make-routes dev)
app (make-app-stack routes db)
{:port (Integer. (nth args 0 3000))
:route routes
:dev dev
:db db
:app app})
(defn start [state]
(println "Running in " (if (:dev state) "DEVELOPMENT" "PRODUCTION") " mode")
(model/create-tables (:db state))
(jetty/run-jetty (:app state) {:port (:port state)}))
(defn -main [& args]
(start (init-state args false)))
make-routes
генерирует маршрутизатор на основе библиотеки compojure
, а make-app-stack
затем упаковывает этот маршрутизатор в связку промежуточного программного обеспечения, которая вводит глобальное состояние (например, строку БД) для использования обработчиками.
Так как мне добавить wrap-reload
к этой настройке? Макрос #'app
не будет работать с локальной let
«переменной» (или как там она называется). Нужно ли выставлять мое приложение как глобальную переменную? Или я могу заново сгенерировать полное замыкание по каждому запросу.
Мои инстинкты говорят мне, чтобы я не держал код глобальной инициализации в теле модуля и держал весь код в main
, но, возможно, я слишком много думаю. Должен ли я просто ввести свой код init-state
как глобальные и назвать его днем, или есть лучший способ?