BackgrounDRb offers seamless integration with rails. You can invoke random tasks defined in your workers from rails. You can pass arguments, collect results, monitor status of workers and other stuff.
Invoke an asynchronous task on a worker :
Let’s say, you have following worker code:
class FooWorker < BackgrounDRb::MetaWorker
set_worker_name :foo_worker
def create(args = nil)
# this method is called, when worker is loaded for the first time
end
def some_task args
# perform a long running task
end
end
And you want to invoke some_task method with appropriate arguments from rails.
Following snippet will invoke method some_task with argument data in foo_worker. Also, method will
be invoked asynchronously and Rails won’t wait for result from BackgrounDRb server.
worker = MiddleMan.worker(:foo_worker) worker.async_some_task(:arg => data)
It should be noted that, since some_task method is being
executed asynchronously, don’t expect any meaningful return values from method invocation.
If you want to invoke a method on worker and collect results returned by it, you
should read next section (Invoke method and collect results).
When you invoke MiddleMan.worker(:foo_worker) it returns a worker proxy, hence you can combine above two lines in
one as follows:
MiddleMan.worker(:foo_worker,<optional_worker_key>).
async_some_task(:arg => data)
Above snippet also demonstrates that, if your worker was started with a worker_key you can use it to
get correct worker proxy.
Invoke a method on worker and get results :
Following snippet will invoke method some_task with argument data in foo_worker. Also, method will block
until BackgrounDRb server returns a result.
worker = MiddleMan.worker(:foo_worker) result = worker.some_task(:arg => data)
Since, now you are expecting a return value from your worker method, new worker code will look like:
class FooWorker < BackgrounDRb::MetaWorker
set_worker_name :foo_worker
def create(args = nil)
# this method is called, when worker is loaded for the first time
end
def some_task args
billing_result = UserPayment.bill!
return billing_result
end
end
As illustrated above, you can use worker_key or make them in single line too.
Fetch Status/Result Objects of a worker :
If you are using cache in your worker code to store result objects, you can retrieve them from
rails using:
status_obj = MiddleMan.worker(:foo_worker).ask_result(cache_key)
You can as usual use worker_key if worker was started with a worker_key.
Start a Worker :
To start a worker from rails:
used_job_key = MiddleMan.new_worker(:worker => :foo_worker,\
:worker_key => "my_secret_job_key")
Worker key passed here, while starting the worker can be used later for invoking tasks on started worker or for accessing cached result objects and stuff like that.
Important thing to be kept in mind is, when you are creating a worker using above approach, you
must use a unique worker_key while starting the worker. Also, while invoking any of the other methods
like ask_result, worker_info or one of the worker methods, you must user same worker_key.
Worker Statistics:
You can get worker specific information using:
MiddleMan.worker(:foo_worker).worker_info
The return value will look something like:
{:worker=>:foo_worker, :status=>:running, :worker_key=>"hello"}
Information about all currently running workers can be obtained using:
MiddleMan.all_worker_info
Return value will look like:
{"0.0.0.0:11006"=>nil, "0.0.0.0:11008"=>
[{:worker_key=>"", :status=>:running, :worker=>:log_worker},
{:worker_key=>"", :status=>:running, :worker=>:foo_worker}]}
By using following option in your backgroundrb.yml you can cluster more than
one backgroundrb server.
:backgroundrb: :ip: 0.0.0.0 :port: 11006 :environment: production :client: "10.0.0.1:11006,10.0.0.2:11007"
So what happens here is, now BackgrounDRb client will talk to bdrb
servers running on both 10.0.0.1:11006 and 10.0.0.2:11007. So when you invoke
a task like this:
MiddleMan.worker(:foo_worker).async_some_task(:arg => data)
Your task gets executed in round robin manner in specified servers by default. Also, once a server goes down, it will automatically stop participating in clustering and when it comes back, it will be automatically start participating in clustering.
In addition to default round robin task distribution, you can override this behaviour
by passing additional :host option while invoking task from rails.For example:
# run method 'some_task' on all backgroundrb servers
MiddleMan.worker(:hello_worker).async_some_task(:arg => data,
:job_key => session[:user_id],:host => :all)
# run method 'some_task' on only locally configured server
MiddleMan.worker(:hello_worker).async_some_task(:arg => data,
:job_key => session[:user_id],:host => :local)
# run the task on specified server
MiddleMan.worker(:hello_worker).async_some_task(:arg => data,:job_key => \
session[:user_id],:host => "10.0.0.2:11210")