std.scheduler

runner, program, spawn, and scheduled task lifecycle

std.scheduler is a higher-level standard library family in foundation-base. This page explains when to use it, how it fits internally, and where to find the API surface.

1    Motivation

Use this layer when application or tooling code needs the behavior described by the page title without reaching directly into implementation namespaces. The top-level namespace is the starting point; subnamespaces expose more focused building blocks.

2    How to use it

Require the top-level namespace for common workflows, then move to subnamespaces when you need a lower-level primitive. Existing tests under test/std/scheduler and test/std/scheduler_test.clj are the best executable examples for edge cases.

create and inspect a runner

(component/with [runner (runner:create)]
  (runner:info runner))
=> {:executors {:core {:threads 0 :active 0 :queued 0 :terminated false}
                :scheduler {:threads 0 :active 0 :queued 0 :terminated false}}
    :programs {}}

install and trigger a program

(component/with [runner (runner:create)]
  (let [q (java.util.concurrent.LinkedBlockingQueue.)]
    (install runner {:id :hello
                     :type :basic
                     :interval 100
                     :main-fn (fn [_ t] (.put q t))})
    (trigger runner :hello)
    (boolean (.poll q 1000 java.util.concurrent.TimeUnit/MILLISECONDS))))
=> true

3    Internal usage

This library family is used across source, tests, generated examples, and docs tooling. During detailed documentation passes, collect concrete usage with code.manage/find-usages and code.manage/locate-code, then keep only high-signal examples in the page narrative.

4    API

5    std.scheduler Guide

std.scheduler is a system for managing concurrent, scheduled tasks (programs) using a runner abstraction. It handles lifecycle, spawning, and scaling of these tasks.

5.1    Core Concepts

  • Runner: The container for all scheduling logic. It has its own thread pools.n- Program: A definition of a task, including its logic (main-fn), state (create-fn), and frequency (interval).n- Spawn: An executing instance of a program. A single program (like "send-email") might have multiple spawns (workers).

5.2    Usage

5.2.1    Scenarios

5.2.1.1    1. Periodic "Cron" Job

Scenario: Run a cleanup task every minute.

(require '[std.scheduler :as scheduler]\n         '[std.lib :as h])\n\n(def runner (scheduler/runner {:id \"system-runner\"}))\n\n(def cleanup-job\n  {:id :cleanup\n   :interval 60000 ;; 60s\n   :create-fn (constantly {:deleted 0}) ;; Initial state\n   :main-fn (fn [args timestamp]\n              ;; Perform cleanup logic\n              (println \"Cleaning up at\" timestamp)\n              {:count 1}) ;; Return value updates state if merge-fn is defined\n   })\n\n(scheduler/install runner cleanup-job)\n(scheduler/spawn runner :cleanup) ;; Start one instance

5.2.1.2    2. Worker Pool Pattern

Scenario: A job queue that needs multiple workers processing in parallel.

You can define a program and then spawn it multiple times.

(def worker-job\n  {:id :worker\n   :interval 100 ;; Check queue every 100ms\n   :main-fn (fn [_ _]\n              (when-let [job (pop-queue!)]\n                (process job)))\n   ;; Optional: Define limits\n   :min 1\n   :max 5})\n\n(scheduler/install runner worker-job)\n\n;; Scale up\n(dotimes [_ 3]\n  (scheduler/spawn runner :worker))

5.2.1.3    3. Dynamic Scaling

Scenario: Increase workers during high load.

You can programmatically spawn or unspawn instances based on metrics.

(defn check-load [runner]\n  (let [q-size (get-queue-size)]\n    (cond\n      (> q-size 100) (scheduler/spawn runner :worker)\n      (< q-size 10)  (scheduler/unspawn runner :worker))))

unspawn removes one instance, respecting the policy (e.g., kill the :last created one).

5.2.1.4    4. Manual Triggering

Scenario: Force execution immediately (e.g., via Admin UI).

You don't need to wait for the interval.

(scheduler/trigger runner :cleanup)

5.2.1.5    5. Managing State

Scenario: Accumulating results.

The merge-fn allows a program to update its :state atom based on the return value of main-fn.

(def stats-job\n  {:id :stats\n   :interval 1000\n   :create-fn (constantly 0)\n   :main-fn (fn [_ _] (rand-int 10))\n   :merge-fn (fn [old-state new-val]\n               (+ old-state new-val))})\n\n;; Access state\n(scheduler/get-state runner :stats)

6    std.scheduler: A Comprehensive Summary (including submodules)

The std.scheduler module provides a robust and flexible framework for scheduling and managing asynchronous tasks in Clojure applications. It builds upon std.concurrent to leverage thread pools and queues, offering features like program installation, dynamic spawning of tasks, and comprehensive monitoring of task execution. The module is designed to handle various scheduling policies and provides detailed information about running and completed tasks.

6.1    std.scheduler (Main Namespace)

This namespace serves as the primary entry point for the scheduling system, aggregating and re-exporting key functionalities from its submodules. It defines the core Runner component and provides high-level functions for managing scheduled programs.

Core Concepts:

  • Runner Component: The central component that manages scheduled programs and their execution. It encapsulates the underlying executors and program states.n Programs: Definitions of tasks to be scheduled, including their type, execution policy, and associated functions.n Spawns: Individual instances of a running program.

Key Functions:

  • get-spawn, stop-spawn, kill-spawn: Functions for managing individual spawns.n get-all-spawn, count-spawn, list-spawn, latest-spawn, earliest-spawn, list-stopped, latest-stopped, latest, stop-all-spawn, kill-all-spawn, clear, get-state, get-program: Functions for managing all spawns of a program.n runner:start, runner:stop, runner:kill: Lifecycle functions for the Runner.n runner:started?, runner:stopped?, runner:health, runner:info: Status and introspection functions for the Runner.n runner?, runner:create, runner: Predicate and constructors for Runner records.n installed?, create-program, uninstall, install: Functions for managing program definitions.n spawn, unspawn: Functions for dynamically starting and stopping program instances.n trigger: Manually triggers a program's execution.n set-interval: Dynamically adjusts the interval of a running program.n* get-props: Retrieves properties of running spawns.

6.2    std.scheduler.common (Common Scheduler Utilities)

This sub-namespace provides shared helper functions for managing the scheduler's runtime environment, including executor creation and lifecycle management.

Key Functions:

  • new-runtime: Constructs a new runtime environment for the scheduler, including core and scheduler executors.n stop-runtime: Stops all executors within a runtime.n kill-runtime: Forcefully stops all executors within a runtime.n all-ids: Returns all running program IDs.n spawn-form, gen-spawn (macro): Generates spawn-related forms.n* spawn-all-form, gen-spawn-all (macro): Generates forms for all spawns.

6.3    std.scheduler.spawn (Task Spawning and Management)

This sub-namespace provides the core logic for spawning and managing individual task instances (spawns), including their lifecycle, job management, and result handling.

Core Concepts:

  • Spawn Record: Represents a single instance of a running program, tracking its ID, properties, output, state, and exit status.n Jobs: Individual tasks submitted to a spawn.n Program Definitions: Configurable properties for a scheduled program (e.g., type, policy, interval, main-fn, args-fn).

Key Functions:

  • spawn-status: Returns the status of a spawn.n spawn-info: Returns detailed information about a spawn.n spawn?, create-spawn: Predicate and constructor for Spawn records.n set-props, get-props: Sets or retrieves properties of a spawn.n get-job, update-job, remove-job, add-job, list-jobs, list-job-ids, count-jobs: Functions for managing jobs within a spawn.n send-result: Sends a result to a spawn's output.n handler-run: Executes a job's main function and handles results.n create-handler-basic, create-handler-constant, create-handler: Creates different types of job handlers.n schedule-timing: Calculates the timing for the next schedule.n wrap-schedule: Wraps a schedule function.n spawn-save-past: Moves a spawn from running to past.n spawn-loop: Creates the main loop for a spawn.n run: Constructs and starts a spawn loop.n get-all-spawn, get-spawn, count-spawn, list-spawn, latest-spawn, earliest-spawn: Functions for retrieving running spawns.n list-stopped, latest-stopped, latest: Functions for retrieving stopped spawns.n stop-spawn, kill-spawn: Stops or kills a spawn.n stop-all, kill-all: Stops or kills all spawns of a program.n clear: Clears program and past spawn information.n get-state, get-program: Retrieves program state or definition.

6.4    std.scheduler.types (Scheduler Contracts)

This sub-namespace defines Malli schemas (contracts) for scheduler configurations, ensuring type safety and valid input for program definitions.

Key Functions:

  • +runtime+: Schema for runtime options.n +spawn+: Schema for spawn options.n +program+: Schema for program definitions.n* <program>: The main schema for a scheduled program.

6.5    Usage Pattern:

The std.scheduler module is essential for building applications that require automated or periodic task execution. It provides:

  • Flexible Scheduling: Support for various program types (e.g., :basic, :constant) and scheduling policies.n Concurrency Management: Leverages std.concurrent for efficient task execution.n Program Lifecycle: Functions for installing, uninstalling, spawning, and stopping programs.n Monitoring and Introspection: Detailed information about running and completed tasks.n Extensibility: A protocol-driven design allows for custom program types and handlers.

By offering a comprehensive and extensible task scheduling framework, std.scheduler empowers developers to build robust and reliable automated systems.