[Backgroundrb-devel] thread_pooling sleeping
hemant
gethemant at gmail.com
Wed Dec 19 04:18:21 EST 2007
On Dec 19, 2007 1:54 PM, hemant <gethemant at gmail.com> wrote:
>
> On Dec 19, 2007 6:58 AM, Jason LaPier <jason.lapier at gmail.com> wrote:
> > I'm trying to run a single worker that could perform a periodic task
> > for a given user.
> >
> > >From a controller, I imagine something like:
> > def start_job
> > MiddleMan.ask_work(:worker => :foo_worker, :worker_method => :perform_task,
> > :data => { :user_id = current_user.id })
> > end
> >
> > def check_job
> > @status = MiddleMan.ask_status(:worker => :foo_worker)[current_user.id]
> > end
> >
> > My worker is something like:
> > class FooWorker < BackgrounDRb::MetaWorker
> > set_worker_name :foo_worker
> > def create(args=nil)
> > @mutex = Mutex.new
> > @mutex.synchronize do
> > @statuses = {}
> > register_status(@statuses)
> > end
> > end
> >
> > def do_task(some_user_id)
> > thread_pool.defer(some_user_id) do |user_id|
> > user = User.find user_id
> > save_status user_id, :progress, "Starting Task"
> > user.do_some_database_stuff
> > save_status user_id, :progress, "Task Stage 2"
> > user.do_some_other_database_stuff
> > save_status user_id, :progress, "Task Stage 3"
> > save_status user_id, :completed, true
> > end
> > end
> >
> > def save_status(user_id, key, data,)
> > @mutex.synchronize do
> > if @statuses[user_id].nil?
> > @statuses[user_id] = {}
> > @statuses[user_id][:completed] = false
> > end
> > @statuses[user_id][key] = data
> > register_status(@statuses)
> > logger.info "statuses synced for #{user_id}, #{key}, #{data}"
> > end
> > end
> >
> > end
> >
> >
> > Problem is, when I use thread_pool, it gets as far as the first part
> > of the task and then just dies, and the backgroundrb script just
> > outputs "going to sleep for a while" over and over until I kill it. I
> > tried taking out the mutex and the register_status bits and the same
> > problem happens. When I use "Thread.new" in place of the thread_pool
> > line, everything works. However, I get some "Some read error" messages
> > during the "do_task" work. Everything happens like it should - I even
> > ran two sessions concurrently and initiated the task with two
> > different users at the same time. The work gets done; although a bit
> > slowly and with those strange errors. Oddly enough, when I run the
> > jobs from the rails irb console, they go without any error - even if I
> > start a couple jobs for multiple users and spam "MiddleMan.ask_status"
> > while the jobs are still running. (of course, when I start the server
> > using the 'Thread.new' method, I get a "no marshal_dump is defined for
> > class Thread" exception in the backgroundrb_server log. I'm guessing
> > this has something to do with why I'm supposed to be using thread_pool
> > instead of Thread).
> >
> > When I get those read errors, the backgroundrb_debug.log shows "Client
> > disconected" (sic). I don't know if this is normal for rails talking
> > to bgrb or if it's an error. I don't see it on every line, but it
> > seems to coincide with the "some read error" messages in the script.
> >
> > Am I doing something wrong? Anyone have a working example using
> > thread_pool? Also, I've never used Mutex before, so if my usage is
> > off, please let me know.
> >
> > Thanks very much,
>
> Hmm,
>
> I am having a look at the problem. Do not worry about "some read
> error" messages, they just indicate that connection that rails was
> having with backgroundrb server is closed. This happens quite often
> because whenever you do:
>
> MiddleMan.xxx
>
> A new connection to backgroundrb server is initiated and older one is
> closed and at that time you get that message. I put those "puts" for
> debugging purpose.
Hi Jason,
Looks like there is an exception being thrown thats not handled in
your code. Here is my sample worker code, similar to yours. I also got
similar behaviour as you described, but then i set
"Thread.abort_on_exception = true" and also ran backgroundrb in
foreground mode(see README file for details).
And then it turned out, there was an exception being thrown in my code
and hence it was not going beyond first stage. Also, you don't need to
protect register_status() with mutex, but rather you should protect
status variable with a mutex as demonstrated below.
class ErrorWorker < BackgrounDRb::MetaWorker
set_worker_name :error_worker
attr_accessor :worker_status
def create(args = nil)
@worker_status = { }
@status_mutex = Mutex.new
register_status(@worker_status)
Thread.abort_on_exception = true
end
def do_task(user_id)
thread_pool.defer(user_id) do |user_id|
save_status(user_id,:progress,"Started")
t_user = World.find_by_id(user_id)
t_user.change_message
logger.info "message changed"
save_status(user_id,:progress,"message_changed")
t_user.change_name
logger.info "name changed"
save_status(user_id,:progress,"name changed")
t_user.save
end
end
def save_status(user_id,key,data)
@status_mutex.synchronize do
@worker_status[user_id] = { :key => key, :data => data}
end
register_status(@worker_status)
logger.info "status synced for user #{user_id} #{key} #{data}"
end
end
To stress test I did this:
require File.join(File.dirname(__FILE__) + "/../config/environment")
p MiddleMan.ask_status(:worker => :error_worker)
(7..200).to_a.each do |world_id|
MiddleMan.ask_work(:worker => :error_worker, :worker_method =>
:do_task, :data => world_id)
p MiddleMan.ask_status(:worker => :error_worker)
end
and it worked flawlessly.
See if this helps.
--
Let them talk of their oriental summer climes of everlasting
conservatories; give me the privilege of making my own summer with my
own coals.
http://gnufied.org
More information about the Backgroundrb-devel
mailing list