When a client terminates a connection
normalperson at yhbt.net
Wed Nov 28 21:10:40 UTC 2012
Andrew Stewart <boss at airbladesoftware.com> wrote:
> I have run into the following situation several times in the past few months:
> (My stack is Nginx -- Unicorn -- Rails 3.0.12)
> 1. Client clicks a delete link in my webapp.
> 2. Rails starts processing the appropriate destroy action. This updates various things in the database (but not in a single db transaction).
> 3. Client terminates the connection.
> 4. Rails stops executing the destroy action wherever it has got to, leaving the latter part of the action unexecuted and my db inconsistent.
> 5. Rails and Unicorn don't write anything to their logs; Nginx writes a 499.
> This question has been asked before but regrettably I don't
> entirely understand all the solutions proposed :)
> I plan to wrap all the changes made by my destroy action in a single
> db transaction. I'm assuming this will ensure db consistency, even
> when subject to awkward clients. Is that correct?
Yes (assuming all your DB actions in the transaction may be
rolled-back). I'm no expert in DBs, but I recommend you always
use transactions when data consistency is required.
> (I'll probably also move the action's work onto a background process,
> e.g. with delayed job.)
This also works, too, and is likely better if your DB actions take
a long time.
> Now apologies if I'm barking up the wrong tree here...in general is it
> possible to configure Unicorn to buffer the request and:
> - if the client terminates before the request is fully received, don't
> pass it to Rails at all;
> - else pass the complete request to Rails and let Rails execute it
> fully, even if client terminates in the meantime?
Yes. Using the Unicorn::PrereadInput middleware (before Rails or any
other middleware/framework touches env["rack.input"]) should do
everything you want.
> The thread also mentioned Nginx's proxy_ignore_client_abort. If
> that's relevant, has anyone tried it?
I haven't, perhaps Jesse can respond?
On a related note, Tom Burns has/had the same problem. Unlike you,
he wanted to avoid processing the request in as many cases as possible.
The solution he came up with isn't 100% foolproof, either, but his
primary goal was to reduce load on an overloaded system.
I haven't heard back on results of our nasty/crazy solution, though.
If you do combine Tom's solution with yours, you still need to ensure
DB consistency in the app.
More information about the mongrel-unicorn