Gracefully exit the Clojure core.async go on kill loop

I have a top level core.async loop. I want it to work endlessly, at least until I pass it on, so that it stops with CTRL-C or kill or similar. I am currently using java.lang.Runtime / addShutdownHook as follows:

(ns async-demo.core (:require [clojure.core.async :as async :refer [<! >! <!! timeout chan alt! go]])) (defn run [] (go (loop [] (recur)))) (.addShutdownHook (Runtime/getRuntime) (Thread. #(println "SHUTDOWN"))) 

Here are my problems:

  • If I run REPL and (run) , then it starts and starts in the background thread. When I exit REPL, I do not see the desired completion message.

  • However, when I run from lein run , the go loop immediately exits and displays "SHUTDOWN".

I do not want either.

I do not necessarily expect to find a solution that works for all JVMs. I am developing on a Mac and deploying Ubuntu, so I would like to find a solution that works for both:

  • Mac JVM: java version "1.7.0_45" Java (TM) SE Runtime Environment (build 1.7.0_45-b18) Java Virtual Machine HotSpot β„’ TM (build 24.45-b08, mixed mode)

  • Ubuntu JVM: java version "1.7.0_25" OpenJDK runtime (IcedTea 2.3.10) (7u25-2.3.10-1ubuntu0.12.04.2) 64-bit server version of OpenJDK (build 23.7-b01, mixed mode)

+9
java signals clojure core.async
source share
3 answers
Function

go returns the channel. You may want to (close! chan) when shutting down.

If you run lein run , you will need a main function that will call (run) to start the thread.

 (ns async-demo.core (:require [clojure.core.async :as async :refer [<! >! <!! timeout chan alt! go close!]])) (def ch (atom nil)) (defn run [] (go (while true (<! (timeout 500)) (prn "inside go")))) (defn -main [& args] (println "Starting") (reset! ch (run)) (.addShutdownHook (Runtime/getRuntime) (Thread. #(do (println "SHUTDOWN") (close! @ch)))) (while true (<!! @ch))) 
+1
source share

You can use exit-ch signaling and fulfill the condition to see whether to exit the loop. Channel + conditional is better handled in clojure by alt! :

 (ns async-demo.core (:require [clojure.core.async :refer [chan go-loop alt! timeout put!]])) (defn run [] (let [exit-ch (chan)] (go-loop [] (alt! (timeout 10) (recur) exit-ch nil exit-ch (let [exit-ch (run)] (.addShutdownHook (Runtime/getRuntime) (put! exit-ch true))) 

If you are just close! channel, it will not stop the cycle. In addition, you do not need to run the go block just to send the value to the channel .

0
source share

Regarding part 1: "When I exit the REPL, I do not see the desired completion message." I think the disconnect thread is not connected to the lein repl console.

Regarding part 2: After the go loop starts, it runs in the background thread. Since the main thread exits after creating the go block, the program shuts down. To make a cycle durable, you need to put it in a regular loop . (It’s also better to add Thread/sleep inside!)

-2
source share

All Articles