172 lines
4.6 KiB
Markdown
172 lines
4.6 KiB
Markdown
|
|
# Metronome
|
||
|
|
|
||
|
|
## Description
|
||
|
|
|
||
|
|
Metronome is an interval scheduler and task runner. It can be used
|
||
|
|
locally as a cron replacement, or as a network-wide job executor.
|
||
|
|
|
||
|
|
Events are stored via simple database rows, and optionally managed
|
||
|
|
via AMQP events. Interval/time values are expressed with intuitive
|
||
|
|
English phrases, ie.: 'at 2pm', or 'Starting in 20 minutes, run every 10
|
||
|
|
seconds and then finish in 2 days', or 'execute 12 times during the next
|
||
|
|
minute'.
|
||
|
|
|
||
|
|
## Synopsis
|
||
|
|
|
||
|
|
Here's an example of a simple cron clone:
|
||
|
|
|
||
|
|
```
|
||
|
|
#!ruby
|
||
|
|
|
||
|
|
require 'symphony/metronome'
|
||
|
|
|
||
|
|
Symphony.load_config
|
||
|
|
|
||
|
|
Symphony::Metronome.run do |opts, id|
|
||
|
|
Thread.new do
|
||
|
|
pid = fork { exec opts.delete('command') }
|
||
|
|
Process.waitpid( pid )
|
||
|
|
end
|
||
|
|
end
|
||
|
|
```
|
||
|
|
|
||
|
|
|
||
|
|
And here's a simplistic AMQP message broadcaster, using existing
|
||
|
|
Symphony connection information:
|
||
|
|
|
||
|
|
```
|
||
|
|
#!ruby
|
||
|
|
|
||
|
|
require 'symphony/metronome'
|
||
|
|
|
||
|
|
Symphony.load_config
|
||
|
|
|
||
|
|
Symphony::Metronome.run do |opts, id|
|
||
|
|
key = opts.delete( 'routing_key' ) or next
|
||
|
|
exchange = Symphony::Queue.amqp_exchange
|
||
|
|
exchange.publish( 'hi from Metronome!', routing_key: key )
|
||
|
|
end
|
||
|
|
```
|
||
|
|
|
||
|
|
## Adding Actions
|
||
|
|
|
||
|
|
There are two primary components to Metronome -- getting actions into
|
||
|
|
its database, and performing some task with those actions when the time
|
||
|
|
is appropriate.
|
||
|
|
|
||
|
|
By default, Metronome will start up an AMQP listener, attached to your
|
||
|
|
Symphony exchange, and wait for new scheduling messages. There are two
|
||
|
|
events it will take action on:
|
||
|
|
|
||
|
|
metronome.create:
|
||
|
|
|
||
|
|
Create a new scheduled event. The payload should be a hash. An
|
||
|
|
'expression' key is required, that provides the interval description.
|
||
|
|
Anything additional is serialized to 'options', that are passed to the
|
||
|
|
block when the interval fires. You can populate it with anything
|
||
|
|
your task requires to execute.
|
||
|
|
|
||
|
|
metronome.delete:
|
||
|
|
|
||
|
|
The payload is the row ID of the action. Metronome removes it from
|
||
|
|
the database.
|
||
|
|
|
||
|
|
If you'd prefer not to use the AMQP listener, you can put actions into
|
||
|
|
Metronome using any database methodology you please. When the daemon
|
||
|
|
starts up or receives a HUP signal, it will re-read and schedule out
|
||
|
|
upcoming work.
|
||
|
|
|
||
|
|
|
||
|
|
## Options
|
||
|
|
|
||
|
|
Metronome uses
|
||
|
|
[Configurability](https://rubygems.org/gems/configurability) to determine
|
||
|
|
behavior. The configuration is a [YAML](http://www.yaml.org/) file. It
|
||
|
|
shares AMQP configuration with Symphony, and adds metronome specific
|
||
|
|
controls in the 'metronome' key.
|
||
|
|
|
||
|
|
metronome:
|
||
|
|
splay: 0
|
||
|
|
listen: true
|
||
|
|
db: sqlite:///tmp/metronome.db
|
||
|
|
|
||
|
|
|
||
|
|
### splay
|
||
|
|
|
||
|
|
Randomize all start times for actions by this many seconds on either
|
||
|
|
side of the original execution time. Defaults to none.
|
||
|
|
|
||
|
|
### listen
|
||
|
|
|
||
|
|
Start up an AMQP listener using Symphony configuration, for remote
|
||
|
|
administration of schedule events. Defaults to true.
|
||
|
|
|
||
|
|
### db
|
||
|
|
|
||
|
|
A [Sequel](https://rubygems.org/gems/sequel) connection URI. Currently,
|
||
|
|
Metronome is tested under SQLite and PostgreSQL. Defaults to a SQLite
|
||
|
|
file at /tmp/metronome.db.
|
||
|
|
|
||
|
|
|
||
|
|
## Scheduling Examples
|
||
|
|
|
||
|
|
Note that Metronome is designed as an interval scheduler, not a
|
||
|
|
calendaring app. It doesn't have any concepts around phrases like "next
|
||
|
|
tuesday", or "the 3rd sunday after christmas". If that's what you're
|
||
|
|
after, check out the [chronic](http://rubygems.org/gems/chronic)
|
||
|
|
library instead.
|
||
|
|
|
||
|
|
Here are a small set of example expressions. Feel free to use the
|
||
|
|
*metronome-exp* utility to get a feel for what Metronome anticipates.
|
||
|
|
|
||
|
|
```
|
||
|
|
in 30.5 minutes
|
||
|
|
once an hour
|
||
|
|
every 15 minutes for 2 days
|
||
|
|
at 2014-05-01
|
||
|
|
at 2014-04-01 14:00:25
|
||
|
|
at 2pm
|
||
|
|
starting at 2pm once a day
|
||
|
|
start in 1 hour from now run every 5 seconds end at 11:15pm
|
||
|
|
every other hour
|
||
|
|
run every 7th minute for a day
|
||
|
|
once a day ending in 1 week
|
||
|
|
run once a minute for an hour starting in 6 days
|
||
|
|
10 times a minute for 2 days
|
||
|
|
run 45 times every hour
|
||
|
|
30 times per day
|
||
|
|
start at 2010-01-02 run 12 times and end on 2010-01-03
|
||
|
|
starting in an hour from now run 6 times a minute for 2 hours
|
||
|
|
beginning a day from now, run 30 times per minute and finish in 2 weeks
|
||
|
|
execute 12 times during the next 2 minutes
|
||
|
|
once a minute beginning in 5 minutes
|
||
|
|
```
|
||
|
|
|
||
|
|
In general, you can use reasonably intuitive phrasings. Capitalization,
|
||
|
|
whitespace, and punctuation doesn't matter. When describing numbers,
|
||
|
|
use digit/integer form instead of words, ie: '1 hour' instead of 'one
|
||
|
|
hour'.
|
||
|
|
|
||
|
|
|
||
|
|
## Installation
|
||
|
|
|
||
|
|
```
|
||
|
|
gem install symphony-metronome
|
||
|
|
```
|
||
|
|
|
||
|
|
## Contributing
|
||
|
|
|
||
|
|
You can check out the current development source with Mercurial via its
|
||
|
|
[project page](http://bitbucket.org/mahlon/symphony-metronome).
|
||
|
|
|
||
|
|
After checking out the source, run:
|
||
|
|
|
||
|
|
```
|
||
|
|
$ rake
|
||
|
|
```
|
||
|
|
|
||
|
|
This task will run the tests/specs and generate API documentation.
|
||
|
|
|
||
|
|
If you use [rvm](http://rvm.io/), entering the project directory will
|
||
|
|
install any required development dependencies.
|