Thursday, February 24, 2011

Ruby - Periodic Process

Ruby's sleep is not very accurate and Eventmachine's timer is also not very good. So, If you need to process one periodic job with some interval, this approach might be helpful. There is a compensation for sleep and you just need to define your process.

Here is the Service class.

 class Service  
def initialize
@interval = 1.0
@start_time = Time.now
end
def start
# Update the start-time
@start_time = Time.now
# run loop
loop do
t_start = Time.now
# process the job
process
elapsed = Time.now - t_start
if elapsed > @interval
puts "Error: Job is bigger than Interval.. #{elapsed}"
end
# apply some compensation.
compensation = (Time.now - @start_time) % @interval
sleep (@interval - compensation)
end
end
def process
raise NotImplementedError
end
end


And then, define your jobs in process method.

 class MyService < Service   
def initialize
super
@interval = 2.0
end
def process
puts "time: #{Time.now.to_f.round(3)}"
# do the random job .. it takes upto 1.5 seconds.
sleep rand(150) * 0.01
end
end


Try to run it..

 service = MyService.new  
service.start



And you will get a very accurate intervals

 time: 1298615010.271  
time: 1298615011.271
time: 1298615012.271
time: 1298615013.271
time: 1298615014.271
time: 1298615015.271
time: 1298615016.271
time: 1298615017.271
time: 1298615018.271
time: 1298615019.271
time: 1298615020.271
time: 1298615021.271
time: 1298615022.271
time: 1298615023.271
time: 1298615024.271
time: 1298615025.271
time: 1298615026.271
time: 1298615027.271
time: 1298615028.271
time: 1298615029.271
time: 1298615030.271
time: 1298615031.271
time: 1298615032.271
time: 1298615033.271
time: 1298615034.271
time: 1298615035.271
time: 1298615036.271
time: 1298615037.271
time: 1298615038.271
time: 1298615039.271
time: 1298615040.271
time: 1298615041.271
time: 1298615042.271


Next time, will try to fix Eventmachine timer..

1 comment:

Kevin Horvath said...

Is this code still required or has ruby's time handling gotten better?