Tallboy Tallboy - 1 month ago 3
Ruby Question

How can my block/yield pass a changing variable?

I'm writing the following module to capture

SIGTERM
that gets occasionally sent to my Delayed Job workers, and sets a variable called
term_now
that lets my job gracefully terminate itself before it's complete.

The following code in my module works perfect if I put it inline in my job, but I need it for several jobs and when I put it in a module it doesn't work.

I assume it's not working because it only passes
term_now
one time (when it's false), and even when it returns true it doesn't pass it again, therefore it never stops the job.

module StopJobGracefully

def self.execute(&block)
begin
term_now = false
old_term_handler = trap('TERM') do
term_now = true
old_term_handler.call
end

yield(term_now)
ensure
trap('TERM', old_term_handler)
end
end

end


Here's the working inline code how it's normally used (this is the code I'm trying to convert to a module):

class SMSRentDueSoonJob

def perform
begin
term_now = false
old_term_handler = trap('TERM') do
term_now = true
old_term_handler.call
end

User.find_in_batches(batch_size: 1000) do

if term_now
raise 'Gracefully terminating job early...'
end

# do lots of complicated work here
end

ensure
trap('TERM', old_term_handler)
end
end

end

Answer

you basically answered it yourself. in the example code you provided, term_now will only become true when the trap snapped before yield is called.

what you need to do is provide a mechanism that periodically fetches the information, so that you can check within the runs of ie find_in_batches.

so instead of yielding the result, your module should have a term_now method that might return an instance variable @term_now.

Comments