diff --git a/src/chime/core.clj b/src/chime/core.clj index ddbfa2a..3c89ebc 100644 --- a/src/chime/core.clj +++ b/src/chime/core.clj @@ -47,6 +47,9 @@ (doto (Thread. r) (.setName (format "chime-" (swap! !count inc)))))))) +(defprotocol ChimeSchedule + (remaining-chimes [chime-schedule])) + (defn chime-at "Calls `f` with the current time at every time in the `times` sequence. @@ -84,36 +87,42 @@ (let [interrupted? (instance? InterruptedException e)] (when-not interrupted? (log/warn e "Error running scheduled fn")) - (not interrupted?))))] + (not interrupted?)))) + !times (atom (map ->instant times))] (letfn [(close [] (.shutdownNow pool) (deliver !latch nil) (when on-finished (on-finished))) - (schedule-loop [[time & times]] - (letfn [(task [] - (if (try - (f time) - true - (catch Exception e - (try - (exception-handler e) - (catch Throwable e - (log/error e "Error calling Chime exception-handler, stopping schedule")))) - (catch Throwable t - (log/error t (str (class t) " thrown, stopping schedule")))) - - (schedule-loop times) - (close)))] - - (if time - (.schedule pool ^Runnable task (.between ChronoUnit/MILLIS (now) time) TimeUnit/MILLISECONDS) - (close))))] - - (schedule-loop (map ->instant times)) + (schedule-loop [] + (let [time (first @!times)] + (letfn [(task [] + (if (try + (swap! !times rest) + (f time) + true + (catch Exception e + (try + (exception-handler e) + (catch Throwable e + (log/error e "Error calling Chime exception-handler, stopping schedule")))) + (catch Throwable t + (log/error t (str (class t) " thrown, stopping schedule")))) + + (schedule-loop) + (close)))] + + (if time + (.schedule pool ^Runnable task (.between ChronoUnit/MILLIS (now) time) TimeUnit/MILLISECONDS) + (close)))))] + + (schedule-loop) (reify + ChimeSchedule + (remaining-chimes [_] @!times) + AutoCloseable (close [_] (close)) diff --git a/test/chime/core_test.clj b/test/chime/core_test.clj index c2c259b..656b356 100644 --- a/test/chime/core_test.clj +++ b/test/chime/core_test.clj @@ -37,6 +37,20 @@ (t/is @proof)))) +(t/deftest test-remaining-chimes + (let [times [(.plusMillis (Instant/now) 500) + (.plusMillis (Instant/now) 1000)] + !proof (atom nil) + !latch (promise) + sched (chime/chime-at times + (fn [time] + (deliver !latch time)))] + (t/is (= times (chime/remaining-chimes sched))) + @!latch + (t/is (= (drop 1 times) (chime/remaining-chimes sched))) + @sched + (t/is (empty? (chime/remaining-chimes sched))))) + (t/deftest test-on-finished (let [proof (atom false)] (chime/chime-at [(.plusMillis (Instant/now) 500) (.plusMillis (Instant/now) 1000)]