Releases: homer6/frequent-cron
v0.3.2 - Jitter & Probabilistic Firing
Released: April 12, 2026
Patch release fixing a critical 100% CPU bug in daemon mode and adding optional jitter and probabilistic firing controls.
New Features
- Jitter (#30) --
--jitter=<ms>adds random timing variance to each firing interval. Supports--jitter-distribution=<uniform|normal>(default: uniform). Useful for spreading load when many services fire at the same frequency. - Probabilistic firing (#30) --
--fire-probability=<0.0-1.0>skips a percentage of ticks at random. Default is1.0(fire every tick), preserving existing behavior. - Both features are optional, off by default, and persisted in the SQLite database with automatic schema migration for existing installs.
- All four platform service definitions (systemd, launchd, rc.d, SCM) pass the new flags through.
Developer Experience
- Claude Code skill for frequent-cron (#34) -- Added a Claude Code skill (
.claude/skills/frequent-cron/) with command reference and service management instructions, enabling AI-assisted operation of the daemon.
Bug Fixes
- Fix 100% CPU in daemon mode on macOS (#32) -- The
Executor(which creates aboost::asio::io_contextbacked by kqueue on macOS) was constructed beforedaemonize()callsfork(). kqueue file descriptors are not inherited across fork, so the child process ended up with a stale kqueue fd, causingkevent()to returnEBADFon every call -- turning the ASIO event loop into a busy spin instead of sleeping between timer ticks. Fix: movedExecutorconstruction to afterdaemonize(). Affected all daemon-mode executions (both legacy--frequency=andrunsubcommand). - Fix service logs showing no output (#33, #31) --
frequent-cron logs <name>returned empty output for running services. Therunsubcommand was usingsystem()which discards stdout/stderr. Fix: added--service-nameto therunparser, wired aLogManageras the executor'sOutputCallbackso command output is captured viarun_process(), andstartnow passes--service-nameand--data-dirwhen launching the daemon.
Testing
- 18 new unit tests: config (7), executor (7), database (4)
- Total: 95 tests passing (77 existing + 18 new)
Upgrading
Drop-in replacement for v0.3.1. Existing databases are migrated automatically to add the new columns (jitter, jitter_distribution, fire_probability) with backward-compatible defaults.
v0.3.1 - Background Command Fix + Migration Guides
Released: April 8, 2026
Patch release fixing a regression where commands containing backgrounded subprocesses (command &) silently failed in legacy mode. Also adds migration guides and documents the release branch workflow.
Bug Fix
- Fix background commands silently failing in legacy mode (#17) --
daemonize()was closing file descriptors 0-2 instead of redirecting them to/dev/null. This violates POSIX: child processes launched viasystem()inherit the closed FDs, and shells enter a non-conforming state where backgrounded subprocesses silently fail to execute. The fix usesopen("/dev/null", O_RDWR)+dup2()to match the behavior ofdaemon(0, 0).
Documentation
- Migration guide: v0.1 to v0.2
- Migration guide: v0.2 to v0.3
- Git workflow conventions added to CLAUDE.md
Testing
- 6 new regression tests for daemonize FD behavior (
tests/test_daemonize.cc) .gitignoreuses wildcard pattern for test binaries- CI now triggers on release branches (
0.*) in addition to main
Upgrading
Drop-in replacement for v0.3.0. No configuration or CLI changes.
v0.2.1 - Background Command Fix
Released: April 8, 2026
Patch release fixing a regression where commands containing backgrounded subprocesses (command &) silently failed in legacy mode.
Bug Fix
- Fix background commands silently failing in legacy mode (#17) --
daemonize()was closing file descriptors 0-2 instead of redirecting them to/dev/null. This violates POSIX: child processes launched viasystem()inherit the closed FDs, and shells enter a non-conforming state where backgrounded subprocesses silently fail to execute. The fix usesopen("/dev/null", O_RDWR)+dup2()to match the behavior ofdaemon(0, 0).
Testing
- 6 new regression tests for daemonize FD behavior (
tests/test_daemonize.cc) - CI now triggers on release branches (
0.*) in addition to master
Upgrading
Drop-in replacement for v0.2.0. No configuration or CLI changes.
v0.3.0 - Service Manager
Released: April 4th, 2026
Transforms frequent-cron from a single-purpose daemon into a full service manager. Register, start, stop, and monitor multiple named services with a SQLite registry, platform-native service integration, and log capture with rotation. Now runs on Linux, macOS, FreeBSD, and Windows.
What's New
Service Management CLI
frequent-cron install <name> --frequency=<ms> --command=<cmd>-- register a named servicefrequent-cron remove <name>-- unregister and clean upfrequent-cron start <name>-- start a registered servicefrequent-cron stop <name>-- stop a running servicefrequent-cron status [name]-- show status of one or all servicesfrequent-cron list-- tabular display of all registered servicesfrequent-cron logs <name>-- view service log outputfrequent-cron run-- explicit run subcommand (same as legacy mode)- Legacy mode preserved:
frequent-cron --frequency=... --command=...still works identically
SQLite Service Registry
- Services and their state tracked in a local SQLite database
- Schema:
servicestable (name, command, frequency, synchronous) +service_statetable (status, PID, timestamps, execution count) - Cascade delete: removing a service cleans up its state automatically
- WAL journal mode for concurrent access safety
Platform-Native Service Installation
- Linux:
installgenerates systemd unit files at/etc/systemd/system/(root) or~/.config/systemd/user/(user), runssystemctl daemon-reload - macOS:
installgenerates launchd plists at~/Library/LaunchAgents/or/Library/LaunchDaemons/ - FreeBSD:
installgenerates rc.d scripts at/usr/local/etc/rc.d/, enables viasysrc - Windows:
installregisters with the Service Control Manager via Win32CreateServiceAPI removecleans up all platform service definitions
Process Output Capture
- New
run_process()function captures stdout and stderr viapopen - Executor supports optional
OutputCallbackfor log capture - Falls back to
system()when no callback is set (preserving exact legacy behavior)
Log Manager
- Per-service log files at
<data_dir>/logs/<name>.log - Timestamped entries
- Size-based log rotation (default: 10MB, 5 rotated files)
Boot-Start and Auto-Restart
- All platforms start services at boot when installed
- Linux:
Restart=on-failurewith 5s delay via systemd - macOS:
KeepAlive=truevia launchd - FreeBSD: enabled at boot via
sysrc; no auto-restart by default - Windows:
SERVICE_AUTO_STARTvia SCM; configure recovery withsc failure
Data Directory
- Platform-specific defaults:
- Linux:
~/.local/share/frequent-cron(user) or/var/lib/frequent-cron(root) - macOS:
~/Library/Application Support/frequent-cron - FreeBSD:
~/.local/share/frequent-cron(user) or/var/lib/frequent-cron(root) - Windows:
%LOCALAPPDATA%\frequent-cron
- Linux:
- Override with
--data-dir=<path>on any subcommand - Auto-creates
logs/andpids/subdirectories
Testing
- 70 GTest unit tests: config (32), pid_file (3), executor (7), data_dir (4), database (12), process (5), log_manager (7)
- Integration test suites for Linux/macOS/FreeBSD (bash) and Windows (PowerShell)
- Per-platform CI workflows with individual badges: Linux, macOS, FreeBSD (via vmactions/freebsd-vm), Windows (with vcpkg binary caching)
- Wiki auto-sync from
docs/wiki/to GitHub Wiki on push to master
Backward Compatibility
frequent-cron --frequency=1000 --command="echo hi"continues to work identically (legacy mode)- The
runsubcommand is functionally identical to legacy mode - No changes to the core timer/execution engine
New Dependencies
- SQLite3 (
libsqlite3-devon Ubuntu,brew install sqliteon macOS,vcpkg install sqlite3:x64-windows) - CMake minimum version bumped from 3.5 to 3.14 (for GTest FetchContent)
Documentation
- 14 wiki pages in
docs/wiki/: Getting Started, CLI Reference, Service Management, Service Lifecycle, Architecture, Configuration, Logging, Platform Guides, FAQ, Troubleshooting, Contributing, and more - Release notes for all versions in
docs/releases/ - Updated platform guides for macOS, Ubuntu, and Windows
init_script.tplmoved todocs/(preferinstallsubcommand for new setups)
New Files
include/:data_dir.h,database.h,service_registry.h,platform_service.h,log_manager.h,process_runner.hsrc/: corresponding.ccimplementationstests/:test_data_dir.cc,test_database.cc,test_process.cc,test_log_manager.ccdocs/wiki/: 14 wiki pagesdocs/releases/: release notes for all versions
v0.2.0 - Modernize and Expand Platform Support
Released: April 4, 2026
Modernized the codebase and added cross-platform support for macOS and Windows.
What's New
- macOS support: builds and runs on macOS with Homebrew dependencies
- Windows support: builds with MSVC + vcpkg,
#ifdef _WIN32guards throughout - Asynchronous execution mode:
--synchronous=falselaunches commands viafork()(POSIX) orcmd /c start /b(Windows) for non-blocking execution - Modern C++: C++23,
std::shared_ptr,std::chrono,std::ofstreamreplacing C-style I/O - Modern Boost ASIO:
io_context+steady_timerreplacing deprecatedio_service+deadline_timer - Refactored architecture: split monolithic
frequent.ccintoconfig,executor,daemonize,pid_filemodules with public headers ininclude/ - GTest unit tests: 25 tests covering config parsing, PID file, executor behavior
- Integration tests: bash (Linux/macOS) and PowerShell (Windows) test scripts
- GitHub Actions CI: automated builds and tests on Linux, macOS, and Windows
make installandmake testsupport- Platform documentation: installation guides for macOS (launchd), Ubuntu (systemd/init.d), and Windows (Task Scheduler)
Breaking Changes
- CMake minimum version bumped from 2.8 to 3.5
- C++23 standard required
- Replaced
daemon()with manualfork()/setsid()(removes macOS deprecation warning) ParseResult::ERRORrenamed toParseResult::PARSE_ERROR(Windows macro conflict)
Dependencies
- Boost 1.37+ (asio, program_options)
- CMake 3.5+
- C++23 compiler
v0.1.0 - Legacy Build
Released: October 28, 2011
The original release of frequent-cron. A single-file C++ daemon that runs shell commands at millisecond intervals on Linux.
Features
- Millisecond-precision command scheduling via Boost ASIO
deadline_timer - Blocking (synchronous) execution model
- Daemonization via POSIX
daemon() - PID file support for service lifecycle management
- init.d service script template
Dependencies
- Boost 1.37+ (system, program_options)
- CMake 2.8+