I feel stupid, but I have not been able to track this down. The background is that I have Jenkins running on the server, and when triggered it pulls code from Github, compiles it, and then moves the final uberjar to the directory where I keep all the uberjars that run on this server. Then I have an app that should kill all currently running instances. Then Supervisord should step in and restart the instances, using the new uberjars for the new instances.
All of this works, but I have been doing one bit by hand: "kill all currently running instances". I log in as root and run a script that kills the old instances. But just today I wrote a quick Clojure app to automate this for me (the whole app is 50 lines of code, so this is a very small app). To trigger the main action, I thought the app should set a watcher on the final directory where Jenkins moves the uberjars to. When Jenkins moves a new uberjar to the directory, the watch would be triggered and then it could run the "kill all currently running instances" script. However, I assumed that the ""kill all currently running instances"" script would be triggered once each time the uberjar was updated, but instead it seems to be triggered infinitely. Does a JVM app, or a Clojure app, change the dir its in, on launch? Or is the problem in my own code? I'm using Chris Zheng's excellent Hara library for the Watch. This is the main function of my app, which is called on startup: (defn establish-watchers [] "The config contains a hashmap which has a 'watchers' key, which contains a vector that holds hashmaps with 2 keys, one pointing to the directory that should be watched and the other pointing to the command that should be run when the watch is triggered." (let [config (read-string (slurp "/etc/fiit.edn")) watchers (:watchers config)] (doseq [w watchers] (common-watch/add (clojure.java.io/file (:dir-to-watch w)) (keyword (:dir-to-watch w)) (fn [f k _ [cmd file]] (pprint/pprint (:out (sh/sh (:action-to-do w))))) {:types #{:create :modify} :recursive false :async false})))) So if I log in as root and start the app like this: /usr/bin/java -jar /home/jenkins/fiit/fiit-1-standalone.jar Then at the terminal I see this, which I expect: [/home/jenkins/sarr] [/home/jenkins/food_for_all] Those are the 2 directories that it is watching. Then if I trigger Jenkins for the sarr app, Jenkins will pull the sarr code from Github, rebuild the sarr uberjar, and move the uberjar to /home/jenkins/sarr. All of that works just great. And then my app sees there has been a change in /home/jenkins/sarr, and so it calls the command to kill all existing instances of the sarr app. However, instead of doing this once, it starts doing so an infinite number of times. At the terminal I see: (sarr is a Java app, not a Clojure app) "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \nroot 25593 0.0 0.1 5813460 19452 ? Sl 20:28 0:00 /usr/bin/java -cp /home/jenkins/sarr/sarr.jar com.candle.sarr.Main\nroot 25595 0.0 0.1 5813460 19564 ? Sl 20:28 0:00 /usr/bin/java -cp /home/jenkins/sarr/sarr.jar com.candle.sarr.Main\n25593\n25595\n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n25694\n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \nroot 26239 0.0 0.1 5813460 19452 ? Sl 20:28 0:00 /usr/bin/java -cp /home/jenkins/sarr/sarr.jar com.candle.sarr.Main\n26239\n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \nroot 26319 0.0 0.1 5811252 15484 ? Sl 20:28 0:00 /usr/bin/java -cp /home/jenkins/sarr/sarr.jar com.candle.sarr.Main\n26319\n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" "We will kill these processes: \n" I have Supervisord set to run 3 instances of the sarr app, so you can see at first it it is killing these PIDs: 25593 25595 25694 Supervisord restarts these almost instantly, so you can see these processes are launched and instantly killed, all on the same line of output: "We will kill these processes: \nroot 26239 0.0 0.1 5813460 19452 ? Sl 20:28 0:00 /usr/bin/java -cp /home/jenkins/sarr/sarr.jar com.candle.sarr.Main\n26239\n" "We will kill these processes: \nroot 26319 0.0 0.1 5811252 15484 ? Sl 20:28 0:00 /usr/bin/java -cp /home/jenkins/sarr/sarr.jar com.candle.sarr.Main\n26319\n" This goes on for as long as I allow it (it takes Supervisord a long time to quit, because when I am developing new software, I set startretries=500, in Supervisord, exactly so I can experiment like this). I looked here to try to figure out what was going on: https://github.com/zcaudate/hara/blob/55b4eda688a4e616f03bf3740419a69b5c5dd658/src/hara/io/watch.clj As near as I can tell, the main action happens here: (defn run-watcher [watcher] (let [^java.nio.file.WatchKey wkey (.take ^java.nio.file.WatchService (:service watcher))] (doseq [^java.nio.file.WatchEvent event (.pollEvents wkey) :when (not= (.kind event) StandardWatchEventKinds/OVERFLOW)] (let [kind (.kind event) ^java.nio.file.Path path (.watchable wkey) ^java.nio.file.Path context (.context event) ^java.nio.file.Path res-path (.resolve path context) ^java.io.File file (.toFile res-path)] (if (and (= kind StandardWatchEventKinds/ENTRY_CREATE) (.isDirectory file) (-> watcher :options :recursive)) (register-sub-directory watcher (.getPath file))) (if (.isFile file) (process-event watcher kind file)))) (.reset wkey) (recur watcher))) Again, maybe I am being stupid, but it looks to me like the callback is called once per event triggered on that directory. So why would the callback seem to be called an infinite number of times? Does starting or stopping the app trigger a change in the directory (thus triggering the callback again)? -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.