Gnomon

Simple event scheduling for Ruby

Presentation

This library provides an easy-to-use event scheduler for Ruby. This allows easy development of asynchronous time-based triggers. Both intervals and points are available for scheduling.

Installation

Gemfile

gem 'gnomon'

Terminal

gem install -V gnomon

Usage

Introduction

First, a Gnomon scheduler should be created:

require 'gnomon'
sched = Gnomon.new

Managing the scheduler

The scheduler itself is a simple Runify service which can be controlled via the typical methods (startup, shutdown, restart).

sched.startup           # Start the Scheduler Service
sched.restart           # Re-Start the Scheduler Service
sched.shutdown          # Stop the Scheduler Service

Events can then be scheduled by using either the schedule generic method, or one of the three shortcut methods schedule_at, schedule_in, schedule_every.

All four methods take an id argument, which can be used to later de-schedule an event (or a group of events).

Each method also accepts a block, which will be executed when the event triggers. Finally, the *args argument will be passed as-is to the block upon trigger.

Any time an event triggers, a new thread is created around the event's block, to which is passed the event's *args.

Granularity

Internally, the scheduler checks the system clock at regular intervals, and compares the next event in the queue to determine whether it's time to trigger. This means that the scheduler has an inherent "minimal time resolution" - events can not be triggered at smaller intervals than this minimum resolution. So why not set this directly to an infinitesimal value? Simply because the scheduler would basically spend most of its time (and the host's CPU cycles) just checking the system clock.

By default, the granularity is set to 1 second, which is fine for most usages. For sub-second scheduling (or very wide scheduling), the granularity can be set to any value by passing it as argument to the constructor:

require 'gnomon'
sched_ms = Gnomon.new 0.001     # Create a Scheduler with milli-second granularity
sched_h = Gnomon.new 3600       # Create a Scheduler with hour granularity

Scheduling events

schedule id, mode, mode_options, timespec, *args, &block

The mode argument can be one of the following:

  • :at -> Trigger the event once at a given date/time (provided by the timespec argument)
  • :in -> Trigger the event once after a certain amount of time has passed (provided by the timespec argument)
  • :every -> Trigger the event periodically at regular intervals (provided by the timespec argument)

Any event scheduled in :at or :in mode will trigger only once, and is automatically de-scheduled after triggering.

The shortcut methods presented below do not perform anything other than call the schedule method with the correct mode argument set.

schedule_at id, date_time, *args, &block

The schedule_at method schedules &block to be run once, at exactly date_time, which can be any string representation of a date/time.

schedule_in id, time, *args, &block

The schedule_in method schedules &block to be run once, in exactly time seconds.

schedule_every id, interval, async, *args, &block

The schedule_every method schedules &block to be run periodically, once every interval seconds. The async argument determines when the next run is scheduled for each run:

  • async = true -> The next trigger is scheduled as soon as the event triggers (before running the event's block).
  • async = false -> The next trigger is scheduled as soon as the event block completes.

De-scheduling events

Previously-scheduled events can be de-scheduled through the deschedule method, by specifying the id used during initial scheduling of the event. An optional keep_running argument can be set to true to indicate that any "next scheduled trigger" should remain in the event queue.

Examples

Basic scheduling

#!/usr/bin/env ruby

require 'gnomon'

# Create Scheduler
sched = Gnomon.new

# Events can be scheduled before running the scheduler
sched.schedule_at(nil, "April 1 2000 10:00 AM") { puts 'April fool\'s day!' }

# Start Scheduler
sched.startup

# Events can be scheduled while the scheduler is running
sched.schedule_in(nil, 5.5) { puts 'Five and half seconds have passed :)' }
sched.schedule_every(nil, 0.1, false) { puts 'Refreshing something...' }

# Do something while scheduler is running...

# Shutdown Scheduler
sched.shutdown

Self-de-scheduling event

#!/usr/bin/env ruby

require 'gnomon'

# Create Scheduler
sched = Gnomon.new

# Start Scheduler
sched.startup

# Run this every second, but five times only (have the event de-schedule itself after 5 triggers)
counter = 0
sched.schedule_every(:foo_task, 1, false) { puts "Run ##{counter}"; sched.deschedule :foo_task if counter >= 5 }

# Shutdown Scheduler
sched.shutdown

Passing arguments

#!/usr/bin/env ruby

require 'gnomon'

# Create Scheduler
sched = Gnomon.new

# Start Scheduler
sched.startup

# Events can be scheduled while the scheduler is running
sched.schedule_in(nil, 5.5, 'Hello world!') { |s| puts "Five and half seconds have passed, time to say \"#{s}\"" }
sched.schedule_in(nil, 10, :users, [:foo, :bar]) { |category, entities| puts "Refreshing #{category}: #{entities.join ', '}" }

# Do something while scheduler is running...

# Shutdown Scheduler
sched.shutdown

License

The gem is available as open source under the terms of the MIT License.