hi friends, I was trying out httpkit server, and run-server was not halting the app to listen for connections - I found another sample in the wild where someone ends their .bb file with:
@(promise)
why is this necessary? it's a promise that will never resolve/deref right? in plain old clojure though, I don't think such a thing is necessary for httpkit (is it?)bb seems more aggressive than clojure when shutting down.
compare bb -e '(future @(promise))' and clojure -e '(future @(promise))'.
clojure will wait a bit before shutting down, you need to call shutdown-agents manually but bb does this for you clojure -X or -T (forgot which) has altered this behavior for clojure as well since it just makes more sense for scripts/tools
This is the behavior clojure -X/etc has: https://github.com/clojure/brew-install/blob/3d4829c16deab48d1b3278102f70909f8eae8891/src/main/clojure/clojure/run/exec.clj#L170-L183
but bb simply just calls shutdown-agents at the end of the script
Perhaps I could try to do the daemon thread approach in bb, but so far this worked out ok
I double checked an httpkit server example invoked with -X and it doesn't seem to quit right away:
(ns script)
(require '[org.httpkit.server :refer [run-server]])
(defn handler [_req]
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Hello from http-kit in Babashka!"})
(defn doit [_]
(run-server handler {:port 8080})
(println "Server running at "))
;; @(promise) ; Keeps the server running
$ clj -X script/doit
Server running at
Although httpkit does seem to spawn daemon threads. Not sure why it doesn't quit right away with -X hereAh, it's probably because there is one ServerThread which is not a daemon thread: https://github.com/http-kit/http-kit/blob/eefe7c13c0ed36283d26bf8b2d936e1ae69465a5/src/java/org/httpkit/server/HttpServer.java#L450
Yeah, this is the difference:
(ns script)
(defn doit [_]
(-> (doto (new java.lang.Thread (fn []
(Thread/sleep 1000000)) )
(.setDaemon true)
(.start)))
(println "Server running at "))
So if you remove .setDaemon the script will immediately return with clojure -XOh no, wait, it's not about shutdown-agents, it's about bb doing a System/exit :)
(defn doit [_]
(-> (doto (new java.lang.Thread (fn []
(Thread/sleep 1000000)) )
#_(.setDaemon true)
(.start)))
(println "Server running at ")
(System/exit 0))
This is basically what's happeningI guess if I would change babashka.main to:
(let [exit-code (run args)]
(when-not (zero? exit-code)
(System/exit exit-code)))
+ installing the daemon executor, it would resemble clojure closerLet's see if CI likes this commit or not... https://github.com/babashka/babashka/commit/f4f1d9e94509a08f2b0ae35d9cda0060ba76e7f7
lol:
lein test babashka.agent-test
=== agent-binding-conveyance-test
Too long with no output (exceeded 10m0s): context deadline exceededlocally this test does just terminate though:
$ ./bb -e '(def ^:dynamic *foo* 1) (def a (agent nil)) (binding [*foo* 2] (send-off a (fn [_] *foo*))) (await a) @a'
2With the change in place, this does still work but hangs:
(import '(java.util.concurrent Executors ExecutorService))
(let [fut (.submit ^ExecutorService (Executors/newCachedThreadPool) ^Callable (fn [] 3))]
(prn (.get fut)))
When I call shutdown on the thread pool executor then the script shuts down
I guess this would be a breaking change to bb really.I would revisit this if people were adamant about changing this behavior.
The workaround doesn't seem too tricky, although I wouldn't have figured it out for awhile if I didn't see it in another sample code - maybe just a note would suffice, or somehow tie to httpkit's start call in stderr