Search code examples
javaclojuresignalscore.async

Gracefully exit a Clojure core.async go loop on kill


I have a top-level core.async go loop. I want it to run indefinitely, at least until I signal it to stop with CTRL-C or kill or similar. I'm currently using java.lang.Runtime/addShutdownHook like this:

(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:

  1. If I start the REPL and (run) then it starts and runs in a background thread. When I exit the REPL, I don't see the desired shutdown message.

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

Neither is what I want.

I don't necessarily expect to find a solution that works for all JVM's. I develop on a Mac and deploy to Ubuntu, so I'd 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 HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

  • Ubuntu JVM: java version "1.7.0_25" OpenJDK Runtime Environment (IcedTea 2.3.10) (7u25-2.3.10-1ubuntu0.12.04.2) OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)


Solution

  • go function returns a channel. You may want to (close! chan) in shutdown hook.

    If you run lein run you need a main function that will call (run) to start go 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)))