├── test └── tr │ └── on_test.clj ├── .gitignore ├── project.clj ├── .travis.yml ├── README.md └── src └── tr └── on.clj /test/tr/on_test.clj: -------------------------------------------------------------------------------- 1 | (ns tr.on-test 2 | (:require [tr.on :refer :all] 3 | [clojure.test :refer :all])) 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /doc 2 | /target 3 | /classes 4 | /checkouts 5 | pom.xml 6 | pom.xml.asc 7 | *.jar 8 | *.class 9 | /.lein-* 10 | /.nrepl-port 11 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject spootnik/tron "0.5.4" 2 | :description "TRON: Task Run ON" 3 | :url "https://github.com/pyr/tron" 4 | :dependencies [[org.clojure/clojure "1.7.0"]]) 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: clojure 3 | lein: lein2 4 | jdk: 5 | - oraclejdk8 6 | - oraclejdk7 7 | - openjdk7 8 | branches: 9 | except: 10 | - gh-pages 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TRON: Task Run ON 2 | ================= 3 | 4 | [![Build Status](https://secure.travis-ci.org/pyr/tron.png)](http://travis-ci.org/pyr/tron) 5 | 6 | 7 | TRON lets you schedule tasks for execution using a Java 8 | ScheduledThreadPoolExecutor under the hood. The name is 9 | to make the parallel with UNIX's CRON a bit more evident. 10 | 11 | ## Usage 12 | 13 | TRON exposes very few functions, here is a small example: 14 | 15 | (ns sandbox 16 | (:require [tr.on :as tron])) 17 | 18 | (defn- periodic [] (println "periodic")) 19 | (defn- ponctual [] (println "ponctual")) 20 | 21 | ;; Run the fonction 10 seconds from now 22 | (tron/once ponctual 10000) 23 | 24 | ;; Run the periodic function every second 25 | ;; after the last call 26 | (tron/periodically :foo periodic 1000) 27 | 28 | ;; Run the periodic function every 10 second 29 | (tron/fixed-periodically :foo periodic 10000) 30 | 31 | ;; Cancel the periodic run 5 seconds from now 32 | (tron/once #(tron/cancel :foo) 5000) 33 | 34 | ;; Execute the followin expressions periodically 35 | (tron/do-periodically 5000 36 | (println "hello")) 37 | 38 | ## Installation 39 | 40 | The easiest way to use TRON in your own projects is via Leiningen. 41 | Add the following dependency to your project.clj file: 42 | 43 | [spootnik/tron "0.5.4"] 44 | 45 | If you would rather use maven, you need to specify the clojars 46 | repository dependency and import the tron artifact 47 | 48 | 49 | clojars.org 50 | http://clojars.org/repo 51 | 52 | 53 | 54 | spootnik 55 | tron 56 | 0.5.4 57 | 58 | 59 | ## License 60 | 61 | Copyright (C) 2011 Pierre-Yves Ritschard 62 | 63 | Distributed under the MIT License 64 | 65 | Permission to use, copy, modify, and distribute this software for any 66 | purpose with or without fee is hereby granted, provided that the above 67 | copyright notice and this permission notice appear in all copies. 68 | 69 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 70 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 71 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 72 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 73 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 74 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 75 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 76 | -------------------------------------------------------------------------------- /src/tr/on.clj: -------------------------------------------------------------------------------- 1 | (ns tr.on 2 | "TRON: Task Run ON 3 | 4 | Simple library to schedule jobs on a Java ScheduledThreadPoolExecutor. 5 | Jobs can be scheduled for recurrent execution or for single-time runs. 6 | Jobs can have nicknames to be later decomissioned." 7 | (:import (java.util.concurrent ScheduledThreadPoolExecutor TimeUnit))) 8 | 9 | (defonce 10 | ^{:private true 11 | :doc "Number of threads for the scheduler."} 12 | poolsize (atom 1)) 13 | 14 | (defonce 15 | ^{:private true 16 | :doc "Thread pool for the scheduler."} 17 | pool (atom nil)) 18 | 19 | (defonce 20 | ^{:private true 21 | :doc "Running tasks on the scheduler."} 22 | tasks (atom {})) 23 | 24 | (defonce 25 | ^{:private true 26 | :doc "Shortcut for milliseconds."} 27 | usecs TimeUnit/MILLISECONDS) 28 | 29 | (defn- get-pool 30 | "Initiate a thread-pool for periodic tasks." 31 | [] 32 | (swap! pool #(or % (ScheduledThreadPoolExecutor. @poolsize)))) 33 | 34 | (defn periodically 35 | "Schedule a function for periodic execution. 36 | There are four different calling modes and three 37 | arities to this function: 38 | 39 | * `nickname f init delay`: provide a nickname to the task 40 | for later removal. the task will be executed after an 41 | initial delay and will recur every delay milliseconds. 42 | * `nickname f delay`: execute the same steps, but launch 43 | the first occurence right away. 44 | * `f init delay`: do not provide a nickname for this tasks 45 | * `f delay`: do not provide a nickname and start the first 46 | occurence right away." 47 | ([nickname f init delay] 48 | (let [task (.scheduleWithFixedDelay (get-pool) f init delay usecs)] 49 | (swap! tasks assoc nickname task))) 50 | ([arg1 arg2 arg3] 51 | (if (= (class arg1) clojure.lang.Keyword) 52 | (let [nickname arg1, f arg2, delay arg3] 53 | (periodically nickname f 0 delay)) 54 | (let [f arg1, init arg2, delay arg3] 55 | (.scheduleWithFixedDelay (get-pool) f init delay usecs)))) 56 | ([f delay] 57 | (periodically f 0 delay))) 58 | 59 | (defn fixed-periodically 60 | "Schedule a function for fixed periodic execution. 61 | There are four different calling modes and three 62 | arities to this function: 63 | 64 | * `nickname f init delay`: provide a nickname to the task 65 | for later removal. the task will be executed after an 66 | initial delay and will recur every delay milliseconds. 67 | * `nickname f delay`: execute the same steps, but launch 68 | the first occurence right away. 69 | * `f init delay`: do not provide a nickname for this tasks 70 | * `f delay`: do not provide a nickname and start the first 71 | occurence right away." 72 | ([nickname f init delay] 73 | (let [task (.scheduleAtFixedRate (get-pool) f init delay usecs)] 74 | (swap! tasks assoc nickname task))) 75 | ([arg1 arg2 arg3] 76 | (if (= (class arg1) clojure.lang.Keyword) 77 | (let [nickname arg1, f arg2, delay arg3] 78 | (periodically nickname f 0 delay)) 79 | (let [f arg1, init arg2, delay arg3] 80 | (.scheduleAtFixedRate (get-pool) f init delay usecs)))) 81 | ([f delay] 82 | (fixed-periodically f 0 delay))) 83 | 84 | (defmacro do-periodically 85 | "Wrap expressions in a function and execute them at the 86 | given interval" 87 | [delay & exprs] 88 | `(periodically (fn [] (do ~@exprs)) ~delay)) 89 | 90 | (defn once 91 | "Schedule a function for one-time execution. Optionnaly 92 | provide a nickname for removal." 93 | ([nickname f delay] 94 | (let [cb (fn [] (f) (swap! tasks dissoc nickname)) 95 | task (.schedule (get-pool) cb (long delay) usecs)] 96 | (swap! tasks assoc nickname task))) 97 | ([f delay] 98 | (.schedule (get-pool) f (long delay) usecs))) 99 | 100 | (defn shutdown 101 | "Terminate all scheduled tasks." 102 | [] 103 | (swap! pool (fn [p] (if p (.shutdown p)) nil))) 104 | 105 | (defn cancel 106 | "Remove a task from the scheduled thread pool." 107 | [nickname] 108 | (when-let [task (@tasks nickname)] 109 | (swap! tasks dissoc nickname) 110 | (doto (get-pool) 111 | (.remove task)))) 112 | 113 | (defn init 114 | "Set the number of periodic tasks which can be executed simultaneously." 115 | ([number] 116 | (shutdown) 117 | (swap! poolsize (fn [_] number))) 118 | ([] 119 | (init 1))) 120 | --------------------------------------------------------------------------------