Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send response but continue execution in Sinatra?

I'm making a small sinatra app. It makes a couple of Redis calls, returns the data, and then makes a final Redis call to save "statistics."

So far if I want to terminate the request early (based on the input), I found that I can use halt:

# code code
halt send_blank if is_blocked? SETTINGS, host
# code code

At the very end I want to have something like this:

response.body = JSON.generate(outgoing)
# update user
STATISTICS.hset('u:' + userID, 'data', JSON.generate({'ip' => request.ip, 'time' => Time.now.to_f.to_s}))

Is it possible to send the response and THEN do the 5~ ms redis write, so that the client doesn't have to wait? No matter where or how I put the final statistics redis call, it delays the sending of the response by some ms - can't trick sinatra.

This can easily be accomplished in Node but just writing what I want done and it will fire off after the response has been sent; as far as I understand, the code here will block the execution for about 5ms before shooting back a response though.

I've tried using after .. do filters, and they would work fine except that you cannot pass to them anything other than the data in response.body - meaning you can't pass to the filter anything that isn't going to be outputted! It's possible to avoid this problem by assigning to variable outside the scope of the post("/"), however with 100+ requests per second, I hope you can see how swapping data through "globals" of sorts can become a huge problem.

It seems like something really simple but I can't find anything better than after .. do filters in the docs.

Can I create a thread or something to make the redis.hset() process non-blocking, will that work? Seems like hacking it hardcore.

Thanks!

like image 814
dsp_099 Avatar asked Sep 08 '12 05:09

dsp_099


1 Answers

Forking the redis write should work.

Something like this:

response.body = JSON.generate(outgoing)
fork do
    # update user
    redis = Redis.new(:host => "your_host_name", :port => your_port_number)
    redis.hset('u:' + userID, 'data', JSON.generate({'ip' => request.ip, 'time' => Time.now.to_f.to_s}))
end
like image 170
Riccardo Marotti Avatar answered Oct 08 '22 11:10

Riccardo Marotti