2

I'm interested in running some server-side code in Rails only after a page has been flushed to a client (similar to the question asked here for Django). Arguably, what I'm looking for is functionality equivalent to Django's request_finished signal for Rails.

I've found callback support for ActiveRecord (which acts on persistance to the database, rather than on request status), and tools for deferring a long-running task intended to allow a page response to complete (but which make no effort no support starting that task only after a page is flushed to the client).

[The immediate use case is processing a user-requested action which can disrupt the running service; the goal is to get the current page out to the client before proceeding with that disruptive action, without anything so race-prone and generally hacky as a hardcoded delay].

Is what I'm trying to accomplish possible? My target is Rails 4.x.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • I'm not sure I get the distinction in use cases, why wouldn't something like delayed job work? – Dave Newton Aug 14 '14 at 00:58
  • Are you ok relying on javascript? Should be easy to fire an ajax request when the DOM has finished loading – l85m Aug 14 '14 at 01:52
  • You could use a background worker or a thread. No reason to awkwardly hook into an after flush event. – Damien Roche Aug 14 '14 at 03:04
  • @DaveNewton, the thing that's hacky with a delayed job is having it be an _arbitrary_ delay -- means you're either delaying too much or risking not delaying enough (particularly in a case where, say, the thread handling the request is paused in a debugger), vs having a trigger or callback which acts as soon as possible but not before. – Charles Duffy Aug 14 '14 at 18:28

2 Answers2

0

If you're ok using Javascript then you can do this:

function pageLoadCallback(){
    $.ajax({ 
        // tell server to do something now that the page is loaded
    })    
}

$(document).ready(function(){
    pageLoadCallback();
});
l85m
  • 808
  • 1
  • 10
  • 19
-1

Take a look at https://github.com/celluloid/celluloid for some starting point for what you are trying to do, basically (as I understand) you have a taks that takes a long time to enqueue and you want that deferred until after you have completed the request to the client..

Two common ways to do that:

  1. Thread.new { HeavyWeightTask.new.enqueue } - (simple by a lot of thread life and death)
  2. Or include Celluloid in the task class and then call HeavyWeightTask.new.async.enqueue (also simple but uses a thread pool)
nort
  • 1,625
  • 13
  • 12
  • Actually, the tasks _don't_ take a long time at all -- I could block the server from answering other requests during their execution and it'd be perfectly fine. However, they must not execute until after the request is flushed to the client, and I'm not sure that either approach mentioned here satisfies that requirement. – Charles Duffy Aug 14 '14 at 14:57
  • I do believe that both provided examples accomplish the goal of allowing the request/response cycle to complete and the connection to the server to close. Then the work would start on the new thread (1) or a member of the thread pool (2) – nort Aug 14 '14 at 19:12
  • 1
    This does not answer the question which was to execute some task only after the response was sent. It also uses an approach that Charles stated he was already aware of and did not fit his application. It might accomplish a similar objective, but Charles specifically stated in his question that he had already considered and discarded this type of solution. – l85m Aug 14 '14 at 19:57
  • @nort -- as asked, it's an explicit part of the goal **to start only after the response has been completely flushed to the client**, because if the operation being run -- which can disrupt server operation -- starts before that point, that response may not be received in its entirety. This is why any approach with an arbitrary delay is a bad idea -- either it's too long and the action doesn't run while the user is expecting it to, or it's too short to handle unusual cases (like the paused-in-a-debugger scenario). – Charles Duffy Nov 09 '14 at 23:27