= README for backnob
Backnob is a really simple background processor. Once started workers can be added. When created workers will fork off to do their processing, and return a hash of results for later inspection.
Server Usage: backnob start|stop|restart|run
[start:] Start the server
[stop:] Stop the server
[restart:] Restart the server
[run:] Run the server in the foreground
Client Usage: backnob create|results
[create:] Create and start a worker. Returns the worker key
[results:] Get the results for a worker key.
Options are:
[-h, --help] Show this help message.
[-c FILE, --configuration=FILE] Load a configuration file
[-l ADDRESS, --listen=ADDRESS] Set the listen address. Defaults to 127.0.0.1:6444
[-p DIR, --pid=DIR] Set the directory for storing the pid and log files. Defaults to /tmp
[-v, --version] Show the version
== Configuration File Options
[:workers] Array of worker files or directories
[:listen] Address to listen on. Default is 127.0.0.1:6444
== Using the library
A simple worker example (simple.rb):
class SimpleWorker < Backnob::Worker
def execute
contents = File.read(@options[:file])
File.open('simple.txt', 'a') do |file|
file.write contents
end
results(:size, File.size('simple.txt'))
end
end
Now start up a backnob server instance by running
backnob start
Using the worker from irb:
require 'rubygems'
require 'backnob/client'
client = Backnob::Client.new
client.add_worker('simple.rb')
key = client.create_worker('simple', :file => '/tmp/to_be_read.txt')
while !client.results(key, :finished)
sleep 1
end
unless client.results(key, :error)
puts "File length is now: #:size)"
end
= Using from Rails
Install the plugin:
svn co svn://rubyforge.org/var/svn/backnob/trunk/plugin vendor/plugins/backnob
rake backnob:setup
Edit config/backnob.yml as appropriate. Create workers in lib/backnob_workers. Workers must
specify "rails true" for the rails environment to be required in. It's not a great idea
to require the environment manually as this will load rails into the server as well as the
worker.
A simple example of a rails worker that imports a CSV file formatted "email, name" into a users table:
require 'csv'
class ImportWorker < Backnob:Worker
rails true
def execute
file = @options[:file]
return unless File.exists? file
records = CSV.parse(File.read(file))
records.each_with_index do |record, index|
results(:progress, (index.to_f / records.length) * 100)
unless User.find_by_email record[0]
User.create(:email => record[0],
:name => record[1],
:active => true)
end
end
end
end
Now in a controller:
class ImportController < ApplicationController
def import
return unless request.post?
file = Tempfile.new('import')
file.write params[:file].read
file.close
session[:import_key] = backnob.create_worker('import', :file => file.path)
render :action => 'wait'
end
def ajax_check_import_progress
results = backnob.results(session[:import_key])
unless results[:finished]
render :update do |page|
page.replace_html 'progress', results[:progress].to_i.to_s
end
else
render :update do |page|
page.redirect_to :action => 'success.rhtml'
end
end
end
end
Views, import.rhtml, wait.rhtml and success.rhtml:
# import.rhtml
<%- form_tag do %>
<%= file_field_tag :file %>
<%= submit_tag %>
<% end -%>
# wait.rhtml
<p> Importing <span id='progress'>0</span>% complete, please wait... <%= image_tag('indicator.gif') %> </p>
<%= update_page_tag do |page|
page << periodically_call_remote :url => => 'ajax_check_import_progress', :frequency => 5
end %>
# success.rhtml
<p> File imported successfully </p>
= Single Workers
A single worker will stay running after execution so you can queue as much work up as you want and it will
execute each bit of work sequentially. Each bit of work still has its own key and results.
An example worker:
class SingleWorker < Backnob::Worker
single true
def execute
@times_run ||= 0
@times_run += 1
work = @options[:work]
logger.info work
results(:run, @times_run)
end
end
Client:
client = Backnob::Client.new
client.add_worker('single_worker.rb')
key1 = client.create_worker('single', :work => "hello")
key2 = client.create_worker('single', :work => "world")
while !client.results(key1, :finished)
sleep 0.25
end
while !client.results(key2, :finished)
sleep 0.25
end
puts client.results(key1, :run) => 1
puts client.results(key2, :run) => 2
Backnob is a really simple background processor. Once started workers can be added. When created workers will fork off to do their processing, and return a hash of results for later inspection.
Server Usage: backnob start|stop|restart|run
[start:] Start the server
[stop:] Stop the server
[restart:] Restart the server
[run:] Run the server in the foreground
Client Usage: backnob create|results
[create:] Create and start a worker. Returns the worker key
[results:] Get the results for a worker key.
Options are:
[-h, --help] Show this help message.
[-c FILE, --configuration=FILE] Load a configuration file
[-l ADDRESS, --listen=ADDRESS] Set the listen address. Defaults to 127.0.0.1:6444
[-p DIR, --pid=DIR] Set the directory for storing the pid and log files. Defaults to /tmp
[-v, --version] Show the version
== Configuration File Options
[:workers] Array of worker files or directories
[:listen] Address to listen on. Default is 127.0.0.1:6444
== Using the library
A simple worker example (simple.rb):
class SimpleWorker < Backnob::Worker
def execute
contents = File.read(@options[:file])
File.open('simple.txt', 'a') do |file|
file.write contents
end
results(:size, File.size('simple.txt'))
end
end
Now start up a backnob server instance by running
backnob start
Using the worker from irb:
require 'rubygems'
require 'backnob/client'
client = Backnob::Client.new
client.add_worker('simple.rb')
key = client.create_worker('simple', :file => '/tmp/to_be_read.txt')
while !client.results(key, :finished)
sleep 1
end
unless client.results(key, :error)
puts "File length is now: #:size)"
end
= Using from Rails
Install the plugin:
svn co svn://rubyforge.org/var/svn/backnob/trunk/plugin vendor/plugins/backnob
rake backnob:setup
Edit config/backnob.yml as appropriate. Create workers in lib/backnob_workers. Workers must
specify "rails true" for the rails environment to be required in. It's not a great idea
to require the environment manually as this will load rails into the server as well as the
worker.
A simple example of a rails worker that imports a CSV file formatted "email, name" into a users table:
require 'csv'
class ImportWorker < Backnob:Worker
rails true
def execute
file = @options[:file]
return unless File.exists? file
records = CSV.parse(File.read(file))
records.each_with_index do |record, index|
results(:progress, (index.to_f / records.length) * 100)
unless User.find_by_email record[0]
User.create(:email => record[0],
:name => record[1],
:active => true)
end
end
end
end
Now in a controller:
class ImportController < ApplicationController
def import
return unless request.post?
file = Tempfile.new('import')
file.write params[:file].read
file.close
session[:import_key] = backnob.create_worker('import', :file => file.path)
render :action => 'wait'
end
def ajax_check_import_progress
results = backnob.results(session[:import_key])
unless results[:finished]
render :update do |page|
page.replace_html 'progress', results[:progress].to_i.to_s
end
else
render :update do |page|
page.redirect_to :action => 'success.rhtml'
end
end
end
end
Views, import.rhtml, wait.rhtml and success.rhtml:
# import.rhtml
<%- form_tag do %>
<%= file_field_tag :file %>
<%= submit_tag %>
<% end -%>
# wait.rhtml
<p> Importing <span id='progress'>0</span>% complete, please wait... <%= image_tag('indicator.gif') %> </p>
<%= update_page_tag do |page|
page << periodically_call_remote :url => => 'ajax_check_import_progress', :frequency => 5
end %>
# success.rhtml
<p> File imported successfully </p>
= Single Workers
A single worker will stay running after execution so you can queue as much work up as you want and it will
execute each bit of work sequentially. Each bit of work still has its own key and results.
An example worker:
class SingleWorker < Backnob::Worker
single true
def execute
@times_run ||= 0
@times_run += 1
work = @options[:work]
logger.info work
results(:run, @times_run)
end
end
Client:
client = Backnob::Client.new
client.add_worker('single_worker.rb')
key1 = client.create_worker('single', :work => "hello")
key2 = client.create_worker('single', :work => "world")
while !client.results(key1, :finished)
sleep 0.25
end
while !client.results(key2, :finished)
sleep 0.25
end
puts client.results(key1, :run) => 1
puts client.results(key2, :run) => 2