Okay, I am an idiot. I had the "directory watch" setup to watch the 
directory where the uberjar was built, so of course it was triggered 
thousands of time while the uberjar was built, since I guess every new byte 
added to the uberjar triggers the change event. 

So I set my app to listen on the final directory, where the final uberjar 
is moved, just once, when the uberjar is complete, and now the app behaves 
the way I was expecting it to. 


On Sunday, August 9, 2015 at 1:13:56 PM UTC-4, Lawrence Krubner wrote:
>
>
> Let's assume for a moment that, for some strange reason, the "directory 
> watching" strategy won't work here. Does anyone have any other suggestions? 
> I am thinking there must be a simple way to setup Jenkins and Supervisord 
> to run these apps, but what I'm doing keeps getting more and more complex, 
> which is typically a warning sign that I'm on the wrong track. 
>
>
>
>
> On Saturday, August 8, 2015 at 5:24:28 PM UTC-4, Lawrence Krubner wrote:
>>
>> 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.

Reply via email to