Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB Ruby driver - `synchronize': can't be called from trap context

Tags:

ruby

mongodb

I'm trying to catch a signal using the Kernel#trap, and run a database request in that context, but I'm getting the above error. Has anyone come across that before? Is there any way around it?

Sample code:

trap('HUP') do
  $db[:db_name].update({_id: 123}, {:$set => {a: 1}})
end

loop { sleep 1 }

Will give this error:

/usr/local/lib/ruby/gems/2.1.0/gems/mongo-1.11.1/lib/mongo/connection/pool.rb:266:in `synchronize': can't be called from trap context (ThreadError)

when the script receives the HUP signal, which can be sent by running kill -HUP {pid}. $db must be a MongoDB object.

like image 642
Matt Parlane Avatar asked Dec 30 '25 21:12

Matt Parlane


1 Answers

Ruby doesn't allow Mutex synchronization from within a trap context, presumably since it can result in deadlocks (ie, you're in a synchronized context, then send the process a signal and attempt to resynchronize, upon which you deadlock). You can reproduce this trivially via:

# trap.rb
require 'thread'
mutex = Mutex.new
trap('HUP') { mutex.synchronize {} }
gets

# pkill -HUP -f trap.rb

trap.rb:3:in `synchronize': can't be called from trap context (ThreadError)
        from trap.rb:3:in `block in <main>'
        from trap.rb:4:in `call'
        from trap.rb:4:in `gets'
        from trap.rb:4:in `gets'
        from trap.rb:4:in `<main>'

To solve this, your signal handler should probably queue a job to be handled by another thread, or you can just spawn a new thread and perform your work in there:

# trap.rb
require 'thread'
mutex = Mutex.new
trap('HUP') do
  Thread.new { mutex.synchronize { puts "hi!" } }
end
gets

# pkill -HUP -f trap.rb
hi!
like image 124
Chris Heald Avatar answered Jan 01 '26 09:01

Chris Heald



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!