{"id":19297446,"url":"https://github.com/factorhouse/cronut","last_synced_at":"2026-01-06T03:17:17.610Z","repository":{"id":60511332,"uuid":"135968155","full_name":"factorhouse/cronut","owner":"factorhouse","description":"A Clojure Companion to Quartz Scheduler","archived":false,"fork":false,"pushed_at":"2025-10-03T00:28:25.000Z","size":151,"stargazers_count":94,"open_issues_count":3,"forks_count":6,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-10-20T21:51:45.288Z","etag":null,"topics":["clojure","quartz","quartz-scheduler","schedule","scheduler","task","task-scheduler"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/factorhouse.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-06-04T03:53:12.000Z","updated_at":"2025-10-07T05:46:49.000Z","dependencies_parsed_at":"2025-01-18T19:52:35.863Z","dependency_job_id":"e97ed7dd-ca4f-4150-b8b5-a4cc43314320","html_url":"https://github.com/factorhouse/cronut","commit_stats":{"total_commits":101,"total_committers":1,"mean_commits":101.0,"dds":0.0,"last_synced_commit":"139cfc88e97e2381fea207c5bff7039fa6742fbe"},"previous_names":["troy-west/cronut"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/factorhouse/cronut","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/factorhouse%2Fcronut","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/factorhouse%2Fcronut/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/factorhouse%2Fcronut/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/factorhouse%2Fcronut/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/factorhouse","download_url":"https://codeload.github.com/factorhouse/cronut/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/factorhouse%2Fcronut/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27673721,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-11T02:00:11.302Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","quartz","quartz-scheduler","schedule","scheduler","task","task-scheduler"],"created_at":"2024-11-09T23:04:55.820Z","updated_at":"2026-01-06T03:17:17.603Z","avatar_url":"https://github.com/factorhouse.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cronut: A Clojure Companion to Quartz\n\n[![Cronut Test](https://github.com/factorhouse/cronut/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/factorhouse/cronut/actions/workflows/ci.yml)\n[![Clojars Project](https://img.shields.io/clojars/v/io.factorhouse/cronut.svg)](https://clojars.org/io.factorhouse/cronut)\n\n# Summary\n\n[Cronut](https://github.com/factorhouse/cronut) provides a data-first [Clojure](https://clojure.org/) wrapper\nfor [Quartz Scheduler](https://github.com/quartz-scheduler/quartz) version `2.5.2`, compatible\nwith [Jakarta](https://en.wikipedia.org/wiki/Jakarta_EE).\n\nCronut supports **in-memory** scheduling of jobs within a single JVM. JDBC and distributed jobstore are not supported.\n\n## Related Projects\n\n| Project                                                             | Desription                                                                                                   | Clojars Project                                                                                                                                 |\n|---------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|\n| [cronut-javax](https://github.com/factorhouse/cronut-javax)         | Cronut with [Javax](https://jakarta.ee/blogs/javax-jakartaee-namespace-ecosystem-progress/) support (Legacy) | [![Clojars Project](https://img.shields.io/clojars/v/io.factorhouse/cronut-javax.svg)](https://clojars.org/io.factorhouse/cronut-javax)         |\n| [cronut-integrant](https://github.com/factorhouse/cronut-integrant) | [Integrant](https://github.com/weavejester/integrant) bindings for Cronut                                    | [![Clojars Project](https://img.shields.io/clojars/v/io.factorhouse/cronut-integrant.svg)](https://clojars.org/io.factorhouse/cronut-integrant) |\n\n# Contents\n\n- [Usage](#usage)\n    * [Scheduler](#scheduler)\n        + [Scheduler lifecycle](#scheduler-lifecycle)\n        + [Scheduling jobs](#scheduling-jobs)\n    * [Jobs](#jobs)\n        + [Job example](#job-example)\n    * [Triggers](#triggers)\n        - [`cronut.trigger/cron`: Simple Cron Scheduling](#cronuttriggercron-simple-cron-scheduling)\n        - [`cronut.trigger/interval`: Simple Interval Scheduling](#cronuttriggerinterval-simple-interval-scheduling)\n        - [`cronut.trigger/builder`: Full trigger definition](#cronuttriggerbuilder-full-trigger-definition)\n    * [Concurrent execution](#concurrent-execution)\n        + [Global concurrent execution](#global-concurrent-execution)\n        + [Job-specific concurrent execution](#job-specific-concurrent-execution)\n        + [Misfire configuration](#misfire-configuration)\n- [Example system](#example-system)\n- [License](#license)\n\n# Usage\n\nA quartz `scheduler` runs a `job` on a schedule defined by a `trigger`.\n\nA `job` or `trigger` is uniquely identified by a `key` consisting of a `name` and (optional) `group`.\n\nA `job` can have multiple `triggers`, a `trigger` is for a single `job` only.\n\n## Scheduler\n\nCronut provides access to the Quartz Scheduler, exposed via the `cronut/scheduler` function.\n\nCreate a scheduler with the following configuration:\n\n1. `:concurrent-execution-disallowed?`: run all jobs with `@DisableConcurrentExecution`\n2. `:update-check?`: check for Quartz updates on system startup.\n\n````clojure\n(cronut/scheduler {:concurrent-execution-disallowed? true    ;; default false\n                   :update-check?                    false}) ;; default false\n````\n\n### Scheduler lifecycle\n\nOnce created, you can:\n\n* `cronut/start`: start the scheduler\n* `cronut/start-delayed`: start the scheduler with a delay\n* `cronut/standy`: temporarily halt the firing of triggers by the scheduler\n* `cronut/shutdown`: stop the scheduler\n* `cronut/pause-all`: pause all triggers\n* `cronut/resume-all`: resume all triggers\n* `cronut/clear`: clear all scheduling data of jobs and triggers\n\n### Scheduling jobs\n\nTo schedule jobs, you can\n\n* `cronut/schedule-job`: schedule a single job\n* `cronut/schedule-jobs`: schedule multiple jobs at once\n* `cronut/pause-job`: pause a job\n* `cronut/resume-job`: resume a paused job\n* `cronut/delete-job`: remove a job from the scheduler\n* `cronut/pause-trigger`: pause a trigger\n* `cronut/resume-trigger`: resume a paused trigger\n* `cronut/unschedule-trigger`: remove a trigger from the scheduler\n\n## Jobs\n\nEach cronut job must implement the `org.quartz.Job` interface.\n\nCronut supports further Quartz configuration of jobs (identity, description, recovery, and durability) by passing an\n`opts` map when scheduling your job.\n\nConcurrent execution can be controlled on a per-job bases with the `disallow-concurrent-execution?` flag.\n\n### Job example\n\n````clojure\n(defrecord TestDefrecordJobImpl [identity description recover? durable?]\n  Job\n  (execute [this _job-context]\n    (log/info \"Defrecord Impl:\" this)))\n\n\n(let [scheduler     (cronut/scheduler {:concurrent-execution-disallowed? true\n                                       :update-check?                    false})\n      defrecord-job (map-\u003eTestDefrecordJobImpl {})\n      reify-job     (reify Job\n                      (execute [_this _job-context]\n                        (let [rand-id (str (UUID/randomUUID))]\n                          (log/info rand-id \"Reified Impl\"))))]\n\n  (cronut/schedule-job scheduler\n                       (trigger/interval 1000)\n                       defrecord-job\n                       {:name        \"name1\"\n                        :group       \"group1\"\n                        :description \"test job 1\"\n                        :recover?    true\n                        :durable?    false})\n\n  (cronut/schedule-job scheduler\n                       (trigger/builder {:type    :cron\n                                         :cron    \"*/5 * * * * ?\"\n                                         :misfire :do-nothing})\n                       reify-job\n                       {:name        \"name2\"\n                        :group       \"group1\"\n                        :description \"test job 2\"\n                        :recover?    false\n                        :durable?    true}))\n```` \n\n## Triggers\n\nCronut triggers are of type `org.quartz.Trigger`, the following functions are provided to simplify trigger creation:\n\n#### `cronut.trigger/cron`: Simple Cron Scheduling\n\nA job is scheduled to run on a cron by using the `cronut.trigger/cron` function with a valid cron expression.\n\nThe job will start immediately when the system is initialized, and runs in the default system time-zone\n\n````clojure\n(cronut.trigger/cron \"*/8 * * * * ?\")\n````\n\n#### `cronut.trigger/interval`: Simple Interval Scheduling\n\nA job is scheduled to run periodically by using the `cronut.trigger/interval` function with a milliseconds value\n\n````clojure\n(cronut.trigger/interval 3500)\n````\n\n#### `cronut.trigger/builder`: Full trigger definition\n\nBoth `cronut.trigger/cron` and `cronut.trigger/interval` are effectively shortcuts to full trigger definition with\nsensible defaults.\n\nThe `cronut.trigger/builder` function supports the full set of Quartz configuration triggers:\n\n````clojure\n;; interval\n(cronut.trigger/builder {:name        \"trigger1\"\n                         :group       \"group3\"\n                         :type        :simple\n                         :interval    3000\n                         :repeat      :forever\n                         :description \"sample simple trigger\"\n                         :start       #inst \"2019-01-01T00:00:00.000-00:00\"\n                         :end         #inst \"2019-02-01T00:00:00.000-00:00\"\n                         :misfire     :ignore\n                         :priority    5})\n\n;;cron\n(cronut.trigger/builder {:name        \"trigger2\"\n                         :group       \"group3\"\n                         :type        :cron\n                         :cron        \"*/6 * * * * ?\"\n                         :description \"sample cron trigger\"\n                         :start       #inst \"2018-01-01T00:00:00.000-00:00\"\n                         :end         #inst \"2029-02-01T00:00:00.000-00:00\"\n                         :time-zone   \"Australia/Melbourne\"\n                         :misfire     :fire-and-proceed\n                         :priority    4})\n````\n\n## Concurrent execution\n\n### Global concurrent execution\n\nSet `:concurrent-execution-disallowed?` on the scheduler to disable concurrent execution of all jobs.\n\n### Job-specific concurrent execution\n\nSet `:disallow-concurrent-execution?` on a specific job to disable concurrent execution of that job only.\n\n### Misfire configuration\n\nIf you disable concurrent job execution ensure you understand Quartz Misfire options and remember to set\n`org.quartz.jobStore.misfireThreshold=[some ms value]` in your quartz.properties file. See Quartz documentation for more\ninformation.\n\nSee our test-resources/config.edn and test-resources/org/quartz/quartz.properties for examples of misfire threshold and\nbehaviour configuration.\n\n# Example system\n\nSee: integration test source: [test/cronut/integration-test.clj](test/cronut/integration_test.clj).\n\n````clojure\n(ns cronut.integration-test\n  (:require [clojure.core.async :as async]\n            [clojure.tools.logging :as log]\n            [cronut :as cronut]\n            [cronut.trigger :as trigger])\n  (:import (java.util UUID)\n           (org.quartz Job)))\n\n(defrecord TestDefrecordJobImpl []\n  Job\n  (execute [this _job-context]\n    (log/info \"Defrecord Impl:\" this)))\n\n(def reify-job (reify Job\n                 (execute [_this _job-context]\n                   (let [rand-id (str (UUID/randomUUID))]\n                     (log/info rand-id \"Reified Impl (Job Delay 7s)\")\n                     (async/\u003c!! (async/timeout 7000))\n                     (log/info rand-id \"Finished\")))))\n\n;(do (require '[cronut.integration-test :as it])\n;    (it/test-system))\n(defn test-system\n  []\n  (let [scheduler (cronut/scheduler {:concurrent-execution-disallowed? true})]\n    (cronut/clear scheduler)\n\n    (async/\u003c!! (async/timeout 2000))\n\n    (log/info \"scheduling defrecord job on 1s interval\")\n    (cronut/schedule-job scheduler\n                         (trigger/interval 1000)\n                         (map-\u003eTestDefrecordJobImpl {})\n                         {:name        \"name1\"\n                          :group       \"group2\"\n                          :description \"test job\"\n                          :recover?    true\n                          :durable?    false})\n\n    ;; demonstrate scheduler can start with jobs, and jobs can start after scheduler\n    (cronut/start scheduler)\n\n    (async/\u003c!! (async/timeout 2000))\n\n    ;; demonstrates concurrency disallowed (every second job runs, 10s interval between jobs that should run every 5s)\n    (log/info \"scheduling reify/7s/no-misfire job on 5s interval\")\n    (cronut/schedule-job scheduler\n                         (trigger/builder {:type    :cron\n                                           :cron    \"*/5 * * * * ?\"\n                                           :misfire :do-nothing})\n                         reify-job\n                         {:name        \"name2\"\n                          :group       \"group2\"\n                          :description \"test job 2\"\n                          :recover?    false\n                          :durable?    true})\n\n    (async/\u003c!! (async/timeout 15000))\n\n    (log/info \"deleting job group2.name1\")\n    (cronut/delete-job scheduler \"name1\" \"group2\")\n\n    (async/\u003c!! (async/timeout 15000))\n\n    (cronut/shutdown scheduler)))\n````\n\n# License\n\nDistributed under the Apache 2.0 License.\n\nCopyright (c) [Factor House](https://factorhouse.io)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffactorhouse%2Fcronut","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffactorhouse%2Fcronut","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffactorhouse%2Fcronut/lists"}