Skip to content

Instantly share code, notes, and snippets.

@arichiardi
Created November 26, 2021 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arichiardi/37563efedcfb69bae28d3577a7c1b891 to your computer and use it in GitHub Desktop.
Save arichiardi/37563efedcfb69bae28d3577a7c1b891 to your computer and use it in GitHub Desktop.
Integrant/Duct dev/prod app -main code
;; This setup solves the problem of prod and dev code path differing at startup.
;; The above issue leads to problems hard to catch, catch when deploying to prod.
;;
;; in production main
;;
(def duct-config-file-path (io/resource "/<project>/config.edn")
(defn prep-config
"Duct prep-config wrapper."
[profiles config-path]
(-> (duct/read-config config-path)
(duct/prep-config profiles)))
(defn -main
[& args]
(logging/info ascii-banner {:args (vec args)})
(let [{:keys [options]} (cli/parse-opts args cli-options)
config-override-path (:config options)
config-path (or (some-> config-override-path io/file) duct-config-file-path)
profiles (->> (:profile options)
(keyword "duct.profile")
vector)]
(logging/info "Application is starting"
{:options options :config-path config-path :profiles profiles})
(alter-var-root #'types/*warn-on-invalid-specs* (constantly false))
(let [system (-> (prep-config profiles config-path)
(ig/init [:duct/daemon]))]
;; NOTE: we do not want to block when we are in dev mode (a REPL is started). It is the REPL
;; that will block the process from exiting.
(when-not (appserver.system/dev? system) (duct/await-daemons system))
system)))
;;
;; In dev.clj or user.clj
;;
(ir/set-prep! #(web.main/prep-config web.main/system-config-file [:duct.profile/dev]))
(def ^:const dev-banner "+-+-+-+-+-+-+-+ |) [- \\/ +-+-+-+-+-+-+-+")
(defn scan-dirs-as-of-now
"Trigger a clojure.tools.namespace scan at the current time.
In order to avoid a hefty first reload we scan for file modifications
from now so that the clojure.tools.namespace thinks that there are no
modified files - we just started the application after all."
[refresh-tracker]
(-> refresh-tracker
(assoc :clojure.tools.namespace.dir/time (System/currentTimeMillis))
(ctn-dir/scan-dirs ctn-repl/refresh-dirs {:platform ctn-find/clj})))
(defn -main
[]
(logging/info dev-banner)
;;
;; Prepare Integrant config
;;
(ir/prep)
;;
;; Delegate system startup to the "production" code path and fill system in
;;
(alter-var-root #'integrant.repl.state/system (fn [_] (web.main/-main "--profile" "dev")))
;;
;; Manually initialize clojure.tools.namespace machinery
;;
(let [refresh-tracker (alter-var-root #'ctn-repl/refresh-tracker scan-dirs-as-of-now)
refresh-stats
{:namespace-count (count (vals (:clojure.tools.namespace.file/filemap refresh-tracker)))
:updated-file-count (count (:clojure.tools.namespace.dir/files refresh-tracker))
:refreshed-at (->> refresh-tracker
:clojure.tools.namespace.dir/time
(tcoerce/from-long)
(tformat/unparse (tformat/formatter :rfc822)))}]
(logging/info "Development system started"
(merge refresh-stats
(when (logging/enabled? :debug)
{:started-keys (into [] (keys integrant.repl.state/system))})))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment