From b21996172057da9b02035c7f236df895bfad6ced Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Sun, 26 Nov 2023 10:01:14 +0100 Subject: [PATCH 1/8] Switch to deps.edn --- .gitignore | 1 + deps.edn | 1 + project.clj | 3 --- src/overtone/at_at.clj | 9 +++++---- 4 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 deps.edn delete mode 100644 project.clj diff --git a/.gitignore b/.gitignore index eee71cb..dd002b7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ pom.xml.asc /.nrepl-port .hgignore .hg/ +.cpcache diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/deps.edn @@ -0,0 +1 @@ +{} diff --git a/project.clj b/project.clj deleted file mode 100644 index 119799e..0000000 --- a/project.clj +++ /dev/null @@ -1,3 +0,0 @@ -(defproject org.alekcz/at-at "1.2.0-SNAPSHOT" - :description "Ahead-of-time function scheduler" - :dependencies [[org.clojure/clojure "1.3.0" :scope "provided"]]) diff --git a/src/overtone/at_at.clj b/src/overtone/at_at.clj index 3dd0f1b..f8ef09d 100644 --- a/src/overtone/at_at.clj +++ b/src/overtone/at_at.clj @@ -3,9 +3,10 @@ [clojure.pprint :as pprint]) (:import (java.io Writer) - (java.util.concurrent ScheduledThreadPoolExecutor - TimeUnit - ThreadPoolExecutor))) + (java.util.concurrent Future + ScheduledThreadPoolExecutor + ThreadPoolExecutor + TimeUnit))) (defrecord PoolInfo [thread-pool jobs-ref id-count-ref]) (defrecord MutablePool [pool-atom]) @@ -303,7 +304,7 @@ pool-info (:pool-info job-info) pool (:thread-pool pool-info) jobs-ref (:jobs-ref pool-info)] - (.cancel ^Future job cancel-immediately?) + (.cancel ^Future job cancel-immediately?) (reset! (:scheduled? job-info) false) (dosync (let [job (get @jobs-ref id)] From 3b4b4f7aad564ce836147f817f8a02ea45ecdde0 Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Sun, 26 Nov 2023 10:08:20 +0100 Subject: [PATCH 2/8] Add lambdaisland-style release tooling --- .gitignore | 1 - bb.edn | 4 ++++ bin/proj | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 bb.edn create mode 100755 bin/proj diff --git a/.gitignore b/.gitignore index dd002b7..902f2bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .cake -pom.xml *.jar *.war lib diff --git a/bb.edn b/bb.edn new file mode 100644 index 0000000..fa0460c --- /dev/null +++ b/bb.edn @@ -0,0 +1,4 @@ +{:deps + {lambdaisland/open-source {:git/url "https://github.com/lambdaisland/open-source" + :sha "b46bd6273c5c554f8374406a7482f6e0a6f1dd25" + #_#_:local/root "../open-source"}}} diff --git a/bin/proj b/bin/proj new file mode 100755 index 0000000..fd44dd2 --- /dev/null +++ b/bin/proj @@ -0,0 +1,14 @@ +#!/usr/bin/env bb + +(ns proj (:require [lioss.main :as lioss])) + +(lioss/main + {:license :epl + :group-id "overtone" + :inception-year 2011 + :description "Ahead-of-time function scheduler."}) + + +;; Local Variables: +;; mode:clojure +;; End: From bc71d237054e0e725b49963e9c7a697e47cfec82 Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Sun, 26 Nov 2023 10:09:04 +0100 Subject: [PATCH 3/8] Set up version prefix --- .VERSION_PREFIX | 1 + pom.xml | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 .VERSION_PREFIX create mode 100644 pom.xml diff --git a/.VERSION_PREFIX b/.VERSION_PREFIX new file mode 100644 index 0000000..7e32cd5 --- /dev/null +++ b/.VERSION_PREFIX @@ -0,0 +1 @@ +1.3 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e957031 --- /dev/null +++ b/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + overtone + at-at + 0.0.51 + at-at + Ahead-of-time function scheduler. + https://github.com/lambdaisland/at-at + 2011 + + Lambda Island + https://lambdaisland.com + + + UTF-8 + + + + Eclipse Public License 1.0 + https://www.eclipse.org/legal/epl-v10.html + + + + https://github.com/lambdaisland/at-at + scm:git:git://github.com/lambdaisland/at-at.git + scm:git:ssh://git@github.com/lambdaisland/at-at.git + 797011be61c92d3e6578e6fcff49fd39eef11b64 + + + + src + + + src + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + 797011be61c92d3e6578e6fcff49fd39eef11b64 + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + + clojars + https://repo.clojars.org/ + + + + + clojars + Clojars repository + https://clojars.org/repo + + + \ No newline at end of file From 33d1f20eb525f149c95a015eff518275866e5c83 Mon Sep 17 00:00:00 2001 From: Daniel MacDougall Date: Tue, 2 Jul 2013 23:27:56 -0400 Subject: [PATCH 4/8] Print warning message when a job throws an exception Fixes #7 --- src/overtone/at_at.clj | 49 ++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/overtone/at_at.clj b/src/overtone/at_at.clj index f8ef09d..6b46fbd 100644 --- a/src/overtone/at_at.clj +++ b/src/overtone/at_at.clj @@ -85,6 +85,17 @@ [] (.availableProcessors (Runtime/getRuntime))) +(declare job-string) + +(defn- wrap-fun-with-exception-handler + [fun job-info-prom] + (fn [& args] + (try + (apply fun args) + (catch Exception e + (println (str e " thrown by at-at task: " (job-string @job-info-prom))) + (throw e))))) + (defn- schedule-job "Schedule the fun to execute periodically in pool-info's pool with the specified initial-delay and ms-period. Returns a RecurringJob record." @@ -92,6 +103,8 @@ (let [initial-delay (long initial-delay) ms-period (long ms-period) ^ScheduledThreadPoolExecutor t-pool (:thread-pool pool-info) + job-info-prom (promise) + ^Callable fun (wrap-fun-with-exception-handler fun job-info-prom) job (if interspaced? (.scheduleWithFixedDelay t-pool fun @@ -105,19 +118,21 @@ TimeUnit/MILLISECONDS)) start-time (System/currentTimeMillis) jobs-ref (:jobs-ref pool-info) - id-count-ref (:id-count-ref pool-info)] - (dosync - (let [id (commute id-count-ref inc) - job-info (RecurringJob. id - start-time - ms-period - initial-delay - job - pool-info - desc - (atom true))] - (commute jobs-ref assoc id job-info) - job-info)))) + id-count-ref (:id-count-ref pool-info) + job-info (dosync + (let [id (commute id-count-ref inc) + job-info (RecurringJob. id + start-time + ms-period + initial-delay + job + pool-info + desc + (atom true))] + (commute jobs-ref assoc id job-info) + job-info))] + (deliver job-info-prom job-info) + job-info)) (defn- wrap-fun-to-remove-itself [fun jobs-ref job-info-prom] @@ -137,8 +152,10 @@ (let [initial-delay (long initial-delay) ^ScheduledThreadPoolExecutor t-pool (:thread-pool pool-info) jobs-ref (:jobs-ref pool-info) - id-prom (promise) - ^Callable fun (wrap-fun-to-remove-itself fun jobs-ref id-prom) + job-info-prom (promise) + ^Callable fun (-> fun + (wrap-fun-with-exception-handler job-info-prom) + (wrap-fun-to-remove-itself jobs-ref job-info-prom)) job (.schedule t-pool fun initial-delay TimeUnit/MILLISECONDS) start-time (System/currentTimeMillis) id-count-ref (:id-count-ref pool-info) @@ -153,7 +170,7 @@ (atom true))] (commute jobs-ref assoc id job-info) job-info))] - (deliver id-prom job-info) + (deliver job-info-prom job-info) job-info)) (defn- shutdown-pool-now! From 1d9c96ab867eb00209009ce4eb795a97239ec74b Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Sun, 26 Nov 2023 12:01:47 +0100 Subject: [PATCH 5/8] Make uncaught-exception-handler customizable Also set name of executor threads to include `at-at`, and doc updates. --- README.md | 33 +++++++++++++++---------------- repl_sessions/walkthrough.clj | 24 +++++++++++++++++++++++ src/overtone/at_at.clj | 37 +++++++++++++++++++++++------------ 3 files changed, 65 insertions(+), 29 deletions(-) create mode 100644 repl_sessions/walkthrough.clj diff --git a/README.md b/README.md index 8aee496..0dbeef1 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,13 @@ Simple ahead-of-time function scheduler. Allows you to schedule the execution of First pull in the lib: ```clj -(use 'overtone.at-at) +(require '[overtone.at-at :as at]) ``` `at-at` uses `ScheduledThreadPoolExecutor`s behind the scenes which use a thread pool to run the scheduled tasks. You therefore need create a pool before you can get going: ```clj -(def my-pool (mk-pool)) +(def my-pool (at/mk-pool)) ``` It is possible to pass in extra options `:cpu-count`, `:stop-delayed?` and `:stop-periodic?` to further configure your pool. See `mk-pool`'s docstring for further info. @@ -52,7 +52,7 @@ It is possible to pass in extra options `:cpu-count`, `:stop-delayed?` and `:sto Next, schedule the function of your dreams. Here we schedule the function to execute in 1000 ms from now (i.e. 1 second): ```clj -(at (+ 1000 (now)) #(println "hello from the past!") my-pool) +(at/at (+ 1000 (at/now)) #(println "hello from the past!") my-pool) ``` You may also specify a description for the scheduled task with the optional `:desc` key. @@ -60,19 +60,19 @@ You may also specify a description for the scheduled task with the optional `:de Another way of achieving the same result is to use `after` which takes a delaty time in ms from now: ```clj -(after 1000 #(println "hello from the past!") my-pool) +(at/after 1000 #(println "hello from the past!") my-pool) ``` You can also schedule functions to occur periodically. Here we schedule the function to execute every second: ```clj -(every 1000 #(println "I am cool!") my-pool) +(at/every 1000 #(println "I am cool!") my-pool) ``` This returns a scheduled-fn which may easily be stopped `stop`: ```clj -(stop *1) +(at/stop *1) ``` Or more forcefully killed with `kill`. @@ -80,13 +80,13 @@ Or more forcefully killed with `kill`. It's also possible to start a periodic repeating fn with an initial delay: ```clj -(every 1000 #(println "I am cool!") my-pool :initial-delay 2000) +(at/every 1000 #(println "I am cool!") my-pool :initial-delay 2000) ``` Finally, you can also schedule tasks for a fixed delay (vs a rate): ```clj -(interspaced 1000 #(println "I am cool!") my-pool) +(at/interspaced 1000 #(println "I am cool!") my-pool) ``` This means that it will wait 1000 ms after the task is completed before @@ -97,13 +97,13 @@ starting the next one. When necessary it's possible to stop and reset a given pool: ```clj -(stop-and-reset-pool! my-pool) +(at/stop-and-reset-pool! my-pool) ``` You may forcefully reset the pool using the `:kill` strategy: ```clj -(stop-and-reset-pool! my-pool :strategy :kill) +(at/stop-and-reset-pool! my-pool :strategy :kill) ``` ### Viewing running scheduled tasks. @@ -111,12 +111,12 @@ You may forcefully reset the pool using the `:kill` strategy: `at-at` keeps an eye on all the tasks you've scheduled. You can get a set of the current jobs (both scheduled and recurring) using `scheduled-jobs` and you can pretty-print a list of these job using `show-schedule`. The ids shown in the output of `show-schedule` are also accepted in `kill` and `stop`, provided you also specify the associated pool. See the `kill` and `stop` docstrings for more information. ```clj -(def tp (mk-pool)) -(after 10000 #(println "hello") tp :desc "Hello printer") -(every 5000 #(println "I am still alive!") tp :desc "Alive task") -(show-schedule tp) -;; [6][RECUR] created: Thu 12:03:35s, period: 5000ms, desc: "Alive task -;; [5][SCHED] created: Thu 12:03:32s, starts at: Thu 12:03:42s, desc: "Hello printer +(def tp (at/mk-pool)) +(at/after 10000 #(println "hello") tp :desc "Hello printer") +(at/every 5000 #(println "I am still alive!") tp :desc "Alive task") +(at/show-schedule tp) +;; [6][RECUR] created: Thu 12:03:35s, period: 5000ms, desc: "Alive task" +;; [5][SCHED] created: Thu 12:03:32s, starts at: Thu 12:03:42s, desc: "Hello printer" ``` ### Install @@ -127,7 +127,6 @@ Fetch at-at from github: https://github.com/overtone/at-at or pull from clojars: at-at was extracted from the awesome music making wonder that is Overtone (http://github.com/overtone/overtone) - ### Authors * Sam Aaron diff --git a/repl_sessions/walkthrough.clj b/repl_sessions/walkthrough.clj new file mode 100644 index 0000000..acc0ece --- /dev/null +++ b/repl_sessions/walkthrough.clj @@ -0,0 +1,24 @@ +(ns at-at.walkthrough + (:require + [overtone.at-at :as at])) + +(def my-pool (at-at/mk-pool)) + +(at/at (+ 1000 (at/now)) #(println "hello from the past!") my-pool) +(at/after 1000 #(println "hello from the past!") my-pool) + +(at/every 1000 #(println "I am cool!") my-pool) +(at/every 1000 #(println "I am cool!") my-pool :initial-delay 2000) +(at/show-schedule my-pool) +(at/stop (first (at/scheduled-jobs my-pool))) + +(at/interspaced 1000 #(println "I am cool!") my-pool) +(at/stop-and-reset-pool! my-pool) +(at/stop-and-reset-pool! my-pool :strategy :kill) + +(def tp (at/mk-pool)) +(at/after 10000 #(println "hello") tp :desc "Hello printer") +(at/every 5000 #(println "I am still alive!") tp :desc "Alive task") +(at/show-schedule tp) + +(run! at/stop (at/scheduled-jobs tp)) diff --git a/src/overtone/at_at.clj b/src/overtone/at_at.clj index 6b46fbd..e1e7572 100644 --- a/src/overtone/at_at.clj +++ b/src/overtone/at_at.clj @@ -3,10 +3,17 @@ [clojure.pprint :as pprint]) (:import (java.io Writer) - (java.util.concurrent Future - ScheduledThreadPoolExecutor - ThreadPoolExecutor - TimeUnit))) + (java.util.concurrent Executors Future ScheduledThreadPoolExecutor ThreadFactory ThreadPoolExecutor TimeUnit))) + +(declare job-string) + +(defn uncaught-exception-handler + "Called when a scheduled function throws. Use `alter-var-root` to customize + this." + [throwable job] + (println (str throwable " thrown by at-at task: " (job-string job))) + (.printStackTrace throwable) + (throw throwable)) (defrecord PoolInfo [thread-pool jobs-ref id-count-ref]) (defrecord MutablePool [pool-atom]) @@ -85,16 +92,13 @@ [] (.availableProcessors (Runtime/getRuntime))) -(declare job-string) - (defn- wrap-fun-with-exception-handler [fun job-info-prom] (fn [& args] (try (apply fun args) - (catch Exception e - (println (str e " thrown by at-at task: " (job-string @job-info-prom))) - (throw e))))) + (catch Throwable t + (uncaught-exception-handler t @job-info-prom))))) (defn- schedule-job "Schedule the fun to execute periodically in pool-info's pool with the @@ -203,7 +207,14 @@ (defn- mk-sched-thread-pool "Create a new scheduled thread pool containing num-threads threads." [num-threads] - (let [t-pool (ScheduledThreadPoolExecutor. num-threads)] + (let [thread-factory (Executors/defaultThreadFactory) + t-pool (ScheduledThreadPoolExecutor. + num-threads + (reify ThreadFactory + (newThread [this runnable] + (let [thread (.newThread thread-factory runnable)] + (.setName thread (str "at-at-" (.getName thread))) + thread))))] t-pool)) (defn- mk-pool-info @@ -371,14 +382,16 @@ "[RECUR] created: " (format-date (:created-at job)) (format-start-time (+ (:created-at job) (:initial-delay job))) ", period: " (:ms-period job) "ms" - ", desc: \""(:desc job) "\"")) + (when (not= "" (:desc job)) + (str ", desc: \"" (:desc job) "\"")))) (defn- scheduled-job-string [job] (str "[" (:id job) "]" "[SCHED] created: " (format-date (:created-at job)) (format-start-time (+ (:created-at job) (:initial-delay job))) - ", desc: \"" (:desc job) "\"")) + (when (not= "" (:desc job)) + (str ", desc: \"" (:desc job) "\"")))) (defn- job-string [job] From 9472540c944d2b64159418c99edac08df0b15403 Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Sun, 26 Nov 2023 12:10:23 +0100 Subject: [PATCH 6/8] README/CHANGELOG --- CHANGELOG.md | 21 ++++++++++++++------- LICENSE => LICENSE.txt | 0 README.md | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 11 deletions(-) rename LICENSE => LICENSE.txt (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d67ff47..a0532d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,10 @@ -# at-at Changelog +# Unreleased -## 1.1.0 -_14th Jan 2013_ - -* Added new fn `interspaced` which will call fun repeatedly with a - specified interspacing. -* Added missing trailing quotes when printing schedule. +- Add exception handling through `uncaught-exception-handler` +- Make our thread pool threads recognizable by adding `at-at` to the thread name +- Add pprint handlers for records +- Add type hints to avoid reflection, and to be Babashka/GraalVM compatible +- Make `shutdown-pool!` public ## 1.2.0 _28th May 2013_ @@ -13,3 +12,11 @@ _28th May 2013_ * BREAKING CHANGE - Remove support for specifying stop-delayed? and stop-periodic? scheduler strategies. * Jobs now correctly report as no longer being scheduled when pool is shutdown. + +## 1.1.0 +_14th Jan 2013_ + +* Added new fn `interspaced` which will call fun repeatedly with a + specified interspacing. +* Added missing trailing quotes when printing schedule. + diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/README.md b/README.md index 0dbeef1..bd2782f 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,30 @@ ### at-at + +[![cljdoc badge](https://cljdoc.org/badge/overtone/at-at)](https://cljdoc.org/d/overtone/at-at) [![Clojars Project](https://img.shields.io/clojars/v/overtone/at-at.svg)](https://clojars.org/overtone/at-at) + + Simple ahead-of-time function scheduler. Allows you to schedule the execution of an anonymous function for a point in the future. > This is a graalvm compatible fork of the original [`overtone/at-at`](https://github.com/overtone/at-at) repo. + +## Installation + +To use the latest release, add the following to your `deps.edn` ([Clojure CLI](https://clojure.org/guides/deps_and_cli)) + +``` +overtone/at-at {:mvn/version "0.0.0"} +``` + +or add the following to your `project.clj` ([Leiningen](https://leiningen.org/)) + +``` +[overtone/at-at "0.0.0"] +``` + + ### Basic Usage First pull in the lib: @@ -119,10 +139,6 @@ You may forcefully reset the pool using the `:kill` strategy: ;; [5][SCHED] created: Thu 12:03:32s, starts at: Thu 12:03:42s, desc: "Hello printer" ``` -### Install - -Fetch at-at from github: https://github.com/overtone/at-at or pull from clojars: `[overtone/at-at "X.Y.Z"]` - ### History at-at was extracted from the awesome music making wonder that is Overtone (http://github.com/overtone/overtone) @@ -133,5 +149,16 @@ at-at was extracted from the awesome music making wonder that is Overtone (http: * Jeff Rose * Michael Neale * Alexander Oloo +* Arne Brasseur +* Daniel MacDougall +* Josh Comer (Ascii art borrowed from http://www.sanitarium.net/jokes/getjoke.cgi?132) + + +## License + +Copyright © 2011-2023 Sam Aaron, Jeff Rose, and contributors + +Available under the terms of the Eclipse Public License 1.0, see LICENSE.txt + From afaacf3d8b8abb3d80b698ba935ec4ada2999539 Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Sun, 26 Nov 2023 12:13:38 +0100 Subject: [PATCH 7/8] Correct the version prefix --- .VERSION_PREFIX | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.VERSION_PREFIX b/.VERSION_PREFIX index 7e32cd5..5625e59 100644 --- a/.VERSION_PREFIX +++ b/.VERSION_PREFIX @@ -1 +1 @@ -1.3 +1.2 From c85040135c5616418e1d44d4cac3bbab4902a623 Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Sun, 26 Nov 2023 12:15:59 +0100 Subject: [PATCH 8/8] More project settings --- bin/proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/proj b/bin/proj index fd44dd2..81722f7 100755 --- a/bin/proj +++ b/bin/proj @@ -5,6 +5,9 @@ (lioss/main {:license :epl :group-id "overtone" + :gh-project "overtone/at-at" + :org-name "Overtone" + :org-url "https://overtone.github.io/" :inception-year 2011 :description "Ahead-of-time function scheduler."})