Gracefully exit a Clojure core.async go loop on kill

clojure, core.async, java, signals

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)))

Problem

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: 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. 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)

Original source

Related problems