Skip to content

Instantly share code, notes, and snippets.

@dariocravero
Created January 5, 2012 16:56
Show Gist options
  • Save dariocravero/1566114 to your computer and use it in GitHub Desktop.
Save dariocravero/1566114 to your computer and use it in GitHub Desktop.
Schedule commands using "at" from ruby.

Ex Ordo Scheduler

What?

Ex Ordo Scheduler is a wrapper written around the at command on Linux:

at, batch, atq, atrm - queue, examine or delete jobs for later execution

It doesn't support all of at's functions but as it is will allow you to queue, dequeue and list scheduled commands. Feel free to change it as you need so :)

How?

You can schedule any command or you can use the shortcut provided to run rake tasks, here're some examples:

ExOrdo::Scheduler::At.schedule(Time.now, 'ls')

ExOrdo::Scheduler::At.schedule(Time.now, {:rake => {:task => 'my:task', :args => [1,4]}})

NOTE. On Mac you'll have to enable atrun for at to work as follows:

sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist

Who's using this?

We're heavily using it on Ex Ordo our software to help academic conferences run smoothly around the globe and save conference organisers loads of time. :)

Enjoy!

# Ex Ordo Scheduler
# https://gist.github.com/1566114
# (c) 2012 Darío Javier Cravero
require 'tempfile'
module ExOrdo
module Scheduler
# Schedule commands with 'at'.
#
# Mac's note
# ----------
# You'll need to run this:
#
# sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist
#
# in order to enable atrun (the utility runs commands queued by at).
#
# http://linuxmanpages.com/man1/at.1.php
module At
# Schedule a job
#
# @param time Date/Time When do you want to queue the job?
# @param command String/Hash Whatever you want to run
def self.schedule(time, command='')
res=`at -t #{parse_time(time)} -f #{encapsulate_command(command)} 2>&1`
sp=res.split(' ')
$?.success? ? sp[sp.index('job')+1] : false
end
# Cancel a job
#
# @param id String The id of the job you'd like to cancel
def self.cancel(id)
if self.pending.map {|p| p[:id]}.include?(id.to_s)
`at -r #{id} 2>&1`
$?.success?
else
false
end
end
# List all the pending jobs
def self.pending
`at -l 2>&1`.split("\n").map do |job|
data = job.split("\t")
{:id => data[0], :date => Time.parse(data[1])}
end
end
# Shortcut to a rake task
#
# @param task String The task to run
# @param args Array The task's params
# @param log String The log's path
def self.rake(task, args=[], log="#{PADRINO_ROOT}/log/rake.log")
params = args.empty? ? '' : "[#{args.join(',')}]"
"bash -l -c 'cd #{PADRINO_ROOT} && bundle exec /usr/local/bin/rake #{task}#{params} --trace 2>&1 >> #{log}'"
end
private
# Parse a time into the format 'at' is expecting
# @param time Date/Time When do you want to queue the job?
def self.parse_time(time)
time.strftime('%Y%m%d%H%M.%S')
end
# Create a temporary file to embed the command 'at' will run.
#
# @param command String/Hash Whatever you want to run
def self.encapsulate_command(command)
file = Tempfile.new('exordo')
file.write(parse_command(command))
file.close
file.path
end
def self.parse_command(command)
if command.is_a?(Hash)
if command.keys.include?(:rake)
return rake(command[:rake][:task],
command[:rake][:args] || [],
command[:rake][:log] || "#{PADRINO_ROOT}/log/rake.log")
end
end
command
end
end
end
end
# Copyright (c) 2012 - Darío Javier Cravero
#
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@DAddYE
Copy link

DAddYE commented Jan 6, 2012

Congrats man!

@dariocravero
Copy link
Author

@DAddYE Thanks!! :) Hope you had a great start of the year!! Please, let me know if it can be improved on any way :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment