How to get a backgroundrb worker to delete itself?

Hi,

I am trying to get a worker instance to delete itself at the end of
its do_work method. I have my main rails app creating these workers
upon certain incoming http requests to parse some XML files, and once
the parsing is complete, I would like the worker to delete itself, so
that I don’t need to try and manage several workers within the main
rails app.

I was trying to accomplish this with the following
line: ::BackgrounDRb::MiddleMan.instance.delete_worker @_job_key.
However, when I tried this, I get the following errer:

20070405-13:15:15 (19653) In do work
20070405-13:15:18 (19653) You have a nil object when you didn’t expect
it!
The error occured while evaluating nil.shutdown - (NoMethodError)

It seems that perhaps this method of trying to access the job key of
the current instance is not working. Has anybody else done something
similar, or have any suggestions for a different method to accomplish
this?

Thanks,

Simon

On a similar note, is there any way to monitor the number of worker
instances that are running? What I am after is to ensure that worker
instances are being deleted, and so I would like to be able to keep an
eye on when new instances are created, and when they are deleted.

Thanks again,

Simon

Hi Simon !

Well, I’m, at the moment , trying to do the same think !!
Looks like calling self.delete at the end of the do_work method of a
worker is a bad idea …
In fact, a worker cannot delete itself, looks like.
What I’m thinking right now would be a sort of … worker that would
act has a cleaner …

Let say, you have a worker that do some email check.

Step1 -> an entry is created in a jobs table with job.cmd = “command
to run the email check”, job.key_job = " unique id for this job" and
job.status = “Waiting”
Step2 -> you have a schedule worker that every 30 minutes, for
example, look at the jobs table, and create worker that have the
waiting status … ( so 1 row in the jobs table becomes a worker soon
or later)
Step3 -> every “waiting” worker that are now running can then update
the “jobs” table to say “hey I’m finish” so job.status = “finished”
Step4 -> the cleaner (the schedule worker that wakes up every 30
minutes) re-check for “Waiting jobs” but also look for “finished jobs”
and clean them … 'cos a woker can clean another one …

Don’t know if that make sence … it is just an “idea” that i’m having
right now … (and it’s 2h00 - not 14h00 !- over here in France :wink: )

Anyway, I might try to implement such a “job cleaner” tomorrow and
have a try …

PS : BUT IF SOMEONE’S GOT AN IDEA ON HOW A WORKER CAN KILL HIMSELF …
I WOULD RATHER TAKE IT !

Jules

Hi Jules,

In fact, a worker cannot delete itself, looks like.

It definitely can. I use the following two lines to do it. The first
makes
sure the database connection doesn’t hang around. The second line looks
just like Simon’s and it works.

ActiveRecord::Base.connection.disconnect!
::BackgrounDRb::MiddleMan.instance.delete_worker @_job_key

Hi Simon,

Simon wrote:

I was trying to accomplish this with the following
line: ::BackgrounDRb::MiddleMan.instance.delete_worker @_job_key.

That looks correct.

However, when I tried this, I get the following errer:

20070405-13:15:15 (19653) In do work
20070405-13:15:18 (19653) You have a nil object when you didn’t expect
it!
The error occured while evaluating nil.shutdown - (NoMethodError)

The error says you’re calling a ‘shutdown’ method on an object that
doesn’t
exist. Maybe you could show us some code?

Bill

Hi Bill,

Thanks for the reply.
I tried the
"::BackgrounDRb::MiddleMan.instance.delete_worker @_job_key " but I
get the same error as Simon :
“The error occured while evaluating nil.shutdown”

now here is the worker :

********* worker code starts here **************

class ProgressWorker < BackgrounDRb::Worker::RailsBase

attr_accessor :temp_key

def do_work(args)

cmdoutput = []
results[:worker_status] = false.to_s

filefrom = "video.mov"
fileto = "video.flv"

encode_cmd='ffmpeg -i '+filefrom+' -b 600k -r 24 -ar 22050 -ab 96

'+fileto

IO.popen(encode_cmd).each do |line|
 cmdoutput << line
 results[:worker_result] = cmdoutput
end


results[:worker_status] = true.to_s
ActiveRecord::Base.connection.disconnect!
::BackgrounDRb::MiddleMan.instance.delete_worker @_job_key

end
end

ProgressWorker.register

********* worker code ends here **************

control calls this worker with :

::MiddleMan.new_worker(:class => :progress_worker)

Now, I’m trying to understand what is going … :

Is this worker properly registered ??? ( I have
ProgressWorker.register after (at the end, end :wink: ) the class
declaration in ProgressWorker.rb …)
@_job_key is an instance variable but … is not defined anywhere ? is
@_job_key automatically created when a worker is called ? if so … may
be I should specify a :job_key when creating it ?

Thanks for all your help !

Julien

yo !

Some improuvment … but not yet finished …

when I logged the @_job_key I receive … an error complaining about
nil string …
I looked in the worker.rb code and found … @jobkey … so I gave it
a try and tada !

when i do :
logger.error(@jobkey) { "Job Key called with @jobkey : "+@jobkey }
I get
20070416-01:34:00 (1269) Job Key called with @jobkey :
34b21fe088389b080578fd83dc1b47ea

but when I do :
logger.error(@jobkey) { "Job Key called with @jobkey : "+@_job_key }
I get
20070416-01:34:00 (1269) can’t convert nil into String - (TypeError)

So sounds liek @_job_key does not exists … but @jobkey does …

(But sorry simon, yhis does not resolve the .shutdown nil for the
moment … I keep seraching …)

jules

Me again … more testing going on …

in the worker, I do :
logger.error(@jobkey) { ::BackgrounDRb::MiddleMan.instance.jobs}

when I look at the log I see :

backgroundrb_logger#Slave:0x24caef8backgroundrb_results#<Slave:
0x24b6318>

Looks like the only workers available are the logger and the
result … where is my worker ???
I understand now why we get :

You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.shutdown - (NoMethodError)

-> there no job with my job_key !

I’m lost …

Hi Jules

Jules wrote:

Now, I’m trying to understand what is going … :

Is this worker properly registered ??? ( I have
ProgressWorker.register after (at the end, end :wink: ) the class
declaration in ProgressWorker.rb …)
@_job_key is an instance variable but … is not defined anywhere ? is
@_job_key automatically created when a worker is called ? if so … may
be I should specify a :job_key when creating it ?

I start the worker with:
session[:job_key] = MiddleMan.new_worker(…

Maybe that’s it?

hth,
Bill

Hi Bill,

I will have a try with the session[:job_key] but …

Looks lile self.delete in the do_work method do the job …
Here is a test to confirm this :

At the end of the do_work method I put this :

results[:worker_status] = true
logger.error(@jobkey) { "Worker status :
"+results[:worker_status].to_s }

And, in return I’ve got in the log : Worker status : true
Now … if I call this instead :

results[:worker_status] = true
self.delete
logger.error(@jobkey) { "Worker status :
"+results[:worker_status].to_s }

I’ve got nothing in my log … why ?
Simply because results for worker are kept until worker is deleted.
So, if i cannot this "Worker status : true " in the log it is because
the worker has been deleted …

So, my conclusion is : self.delete works :wink:

PS : please let me know if you think that this test does not confirm
the fact that calling self.delete, really kill the worker :wink: