[Backgroundrb-devel] thread_pooling sleeping
Jason LaPier
jason.lapier at gmail.com
Wed Dec 19 12:28:02 EST 2007
On Dec 19, 2007 1:18 AM, hemant <gethemant at gmail.com> wrote:
>
> 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.
>
Ok, awesome - thanks very much for your help. With the
abort_on_exception flag and the foreground logging, I was able to
track down the problem. If you try something like:
def do_task(some_user_id)
logger.info "do_task: some_user_id: #{some_user_id.class}"
logger.info "starting task - defer to the thread pool"
thread_pool.defer(some_user_id) do |user_id|
logger.info "user_id (in pool): #{user_id.class}"
# and the rest of it
end
end
You'll see in the log:
do_task: some_user_id: Fixnum
starting task - defer to the thread pool
user_id (in pool): Array
So some_user_id is being converted to [user_id] for the block. Calling
AR's find method with an array gives you back an array (which was the
source of my original exception - trying to act on an Array as if it
were a User object). When you use User.find_by_id in your example, AR
is taking just the first element in the array and doing a find on
that.
I suspect that's a bug in thread_pool, or at least if it's not, it's a
little confusing syntactically. Now that I know how it works, I've got
my code working, so if it's not a bug, no problem :)
- Jason L.
--
My Rails and Linux Blog: http://offtheline.net
More information about the Backgroundrb-devel
mailing list