How to perform some task after render in Rails 3.1
Asked Answered
L

6

12

I'm using Impressionist to record page impressions. The database write only takes about 50ms, but I'd really prefer to do it after the page has rendered and been sent to the client.

I've looked into forking via Spawn, but it establishes a new database connection, which seems to be overkill for such a small job. Delayed Job and other background processing libraries seem like major overkill. Writing to the database just to defer writing to the database...not a win.

I wish I could just:

def show
  render
  impressionist(@article)
end

...and have impressionist do its thing with the same database connection and all the same request data as the action, just after the action has already returned to the client. But of course that's not how the render method works.

Any solutions? Running Rails 3.1 and Ruby 1.9.2 on Heroku Cedar.

Luttrell answered 17/11, 2011 at 12:51 Comment(1)
this is harder than you think :) take inspiration from here: perfectline.ee/blog/ruby-on-rails-before-render-filterCoping
C
6

Spawn a new thread. Heroku will allow you up to 15 threads per dyno.

def show
  render
  Thread.new do
    impressionist(@article)
  end
end
Corrinacorrine answered 19/2, 2013 at 3:43 Comment(1)
The point was, I wanted the process available for a new request. With a thread, you either have to thread.join or the thread terminates when the process terminates.Luttrell
G
1

There is a pretty cool railscast on using Resque for exactly this, but I am pretty sure it also involves forking, as do all other methods I have seen.

Gird answered 24/1, 2012 at 8:49 Comment(0)
L
1

This came along and looks promising: https://github.com/brandonhilkert/sucker_punch

Brandon's a solid dude. Can't wait to try Sucker Punch out!

Luttrell answered 20/2, 2013 at 4:58 Comment(1)
Sucker Punch is a very lightweight gem (the heavy lifting is done in Celluloid), easy to grok. It doesn't give you an admin UI or anything, but it does what it is advertising. Most of the websites don't need multiple servers, but multithreading + CoW comes handy in a VPS environment. It's a nice way to start background processing with no hassle.Trella
V
1

Personally, I wouldn't recommend launching "Thread new" from action and then passing into background thread reference to element(s) which are still manipulated in another thread. Such leads very quickly into nasty non-reproducable bugs due conflicts between threads.

Venule answered 21/7, 2016 at 15:30 Comment(0)
I
0

How about logging to something a bit faster like mongodb, or you could consider storing a hash in redis (ultra fast) and have a batch job run every hour or so to store these in your postgres database. With both of these options you would have to hack impressionist, or roll you own solution which, as you suggested with background solutions (delayed_job, resque etc) may be overkill depending on the size of your project.

Ineradicable answered 19/11, 2011 at 21:36 Comment(0)
S
0

I think you can use after_filter callback function

class ApplicationController < ActionController::Base

  after_filter :after_filter_cb

  def after_filter_cb
    # Some logic
  end

end
Stelly answered 4/11, 2013 at 5:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.