Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Ripple

Ripple is a small Linux event-dispatch daemon. It connects named events to executable handlers and provides one place to trigger those handlers manually, from other programs, or from built-in timers.

The project is intended for lightweight system automation: a producer emits an event without needing to know which scripts respond to it, while handlers can be added or removed through the filesystem. Ripple serializes dispatching, records handler output in the system journal, and controls access through a local Unix socket.

What Ripple does

Ripple runs as a daemon and builds an event registry from executable files in /etc/ripple/handlers. Its command-line client connects to the daemon to:

  • check whether Ripple is available;
  • emit an event with optional arguments;
  • reload the handler registry;
  • list registered events and their handlers; and
  • inspect the built-in timers and whether they are active.

An event may have multiple handlers. Handlers can run synchronously, where Ripple waits for them, or detached in the background. Events named after a built-in timer are emitted automatically on that timer's schedule.

How it works

At startup, the daemon:

  1. Opens /var/run/ripple/ripple.sock.
  2. Restricts the socket to the configured group with mode 0660.
  3. Scans /etc/ripple/handlers for event handlers.
  4. Starts the timers required by the discovered event names.
  5. Notifies systemd that it is ready.
  6. Accepts authenticated local clients and dispatches their requests.

Clients are authenticated using Unix peer credentials. Root and members of the group selected with --gid are allowed to connect.

Event requests enter a single FIFO dispatch queue. This prevents separate event requests from running their synchronous handlers at the same time. Each handler is launched through systemd-cat, so its standard output and standard error are available through the system journal.

CLI or timer
|
v
Unix packet socket
|
v
FIFO event dispatcher
|
+--> synchronous handlers
|
+--> detached handlers

Defining handlers

Ripple discovers handlers by filename. A top-level executable uses the last @ in its filename to separate its name from its event:

/etc/ripple/handlers/backup@daily
/etc/ripple/handlers/update-cache@package-changed
/etc/ripple/handlers/send-report@monthly.d

The supported forms are:

FormMeaning
NAME@EVENTRun NAME synchronously when EVENT is emitted.
NAME@EVENT.dRun NAME as a detached handler for EVENT.
@EVENT/Register executable children of the directory for EVENT.
@EVENT/NAME.dRegister a detached handler inside an event directory.

For example, the following layouts both register handlers for network-ready:

/etc/ripple/handlers/configure-firewall@network-ready
/etc/ripple/handlers/@network-ready/
configure-firewall
announce.d

Handlers must have at least one executable permission bit. Ripple ignores hidden files, common editor or partial-write files, non-executable files, and nested directories inside an event directory. Symbolic links are resolved to their targets before execution.

Every handler receives the emitted event name as its first argument, followed by any arguments supplied to ripple emit. Given:

ripple emit package-changed openssl upgraded

a matching handler is invoked conceptually as:

/path/to/handler package-changed openssl upgraded

Synchronous handlers have a five-second execution timeout. Ripple continues through all synchronous handlers and reports a failure if one or more fail. Detached handlers have no execution timeout, but the same underlying executable cannot run concurrently with itself. If it is already running, another detached invocation is not started.

Built-in timers

A timer is enabled only when the event registry contains an event with the same name. For example, installing an executable named backup@daily activates the daily timer.

Interval timers wait for a fixed duration between dispatches:

EventInterval
1min1 minute
2min2 minutes
5min5 minutes
10min10 minutes
15min15 minutes
30min30 minutes
45min45 minutes
hourly1 hour

Calendar timers run at midnight in the system's local time zone:

EventSchedule
dailyEvery day
weekdayMonday through Friday
weekendSaturday
weeklyMonday
biweeklyMonday in even-numbered ISO weeks
monthlyFirst day of each month
quarterlyJanuary 1, April 1, July 1, and October 1
semiannuallyJanuary 1 and July 1
yearlyJanuary 1

Calendar timer state is persisted in /var/lib/ripple/timers.json. Ripple uses that state to detect a missed occurrence after restart, suspend, hibernation, or a significant forward clock change. A missed occurrence is dispatched when the timer is restored.

Command-line usage

Usage:
ripple [options] [command, ...]
Commands:
status get daemon status
reload re-scan for event handlers
emit EVENT [ARGS] dispatch event
list-events list all available events
list-handlers EVENT list all handlers for a given event
list-timers list all built-in timers
Options:
--daemon run the Ripple dispatch daemon
--gid GROUP group name or numeric gid allowed to use the daemon
-h, --help show help
--wait wait for event completion

Examples:

# Check connectivity and authorization.
ripple status
# Dispatch and acknowledge immediately after the request is accepted.
ripple emit network-ready eth0
# Wait for synchronous handlers and receive their aggregate result.
ripple --wait emit network-ready eth0
# Re-scan the handler directory and update active timers.
ripple reload
# Inspect the registry.
ripple list-events
ripple list-handlers network-ready
ripple list-timers

Without --wait, the daemon starts event dispatch asynchronously and replies immediately. With --wait, the client waits for dispatch to finish. The client uses exit status 254 for handler failure, 253 for dispatch timeout, and 1 for other errors.

Running the daemon

Start Ripple with:

ripple --daemon --gid ripple

--gid accepts either a group name or a numeric group ID. If it is omitted, Ripple uses the primary group of the process starting the daemon.

Ripple currently expects its runtime directories to exist. Before starting the daemon, ensure that these locations are present with permissions appropriate for the service account:

/etc/ripple/handlers
/var/run/ripple
/var/lib/ripple

The daemon is designed to run under systemd and sends a readiness notification after its registry and timers have initialized. Handler execution also requires systemd-cat to be available.

Building from source

Ripple requires Linux and Go 1.25 or later. From the src directory, use the included build script:

cd src
./make

This produces the src/ripple executable. The equivalent Go command is:

go build -buildvcs=false -o ripple ./binary

The source can be checked with:

go test -buildvcs=false ./...
go vet -buildvcs=false ./...
gofmt -d binary events ipc mutex triggers utils

Project structure

src/
├── binary/ daemon entry point and CLI request handling
├── events/ handler discovery, registry, and event execution
├── ipc/ Unix packet socket and protocol types
├── mutex/ synchronization helpers
├── triggers/ built-in timers and persistent timer state
└── utils/ shared map and output utilities

Ripple is distributed under the MIT license terms included in its source files.

About

Linux event-dispatch daemon

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages