Ben
Ben

Reputation: 315

Do something when user aborts connection (Sinatra + Thin)

I'm writing an app that sometimes requires very long-running DB requests. I'd like to execute some code if the client reloads or closes the page to do things with the DB requests.

I was hoping that Rack would have hooks into this sorta thing, but apparently from what I've seen this is a level deeper than Rack goes.

So far, the only hook I can find is into thin itself, by monkey-patching the unbind function in the thin Connection class:

module Thin
  class Connection < EventMachine::Connection

    def unbind

      # DO something here

      @request.async_close.succeed if @request.async_close
      @response.body.fail if @response.body.respond_to?(:fail)
      @backend.connection_finished(self)
    end
  end
end

This overrides Thin's unbind function and lets me hook into the disconnect called by EventMachine.

Is there a better way?

Upvotes: 3

Views: 497

Answers (1)

Ben
Ben

Reputation: 315

After some digging, I've found that Thin provides a mechanism for replacing the 'backend', or how the server connects to the client. I'm using that, combined with values in the rack env to deal with specific request instances and know if I need to kill a query or not:

class Backend < Thin::Backends::TcpServer

  def initialize(host, port, options={})
    super(host, port)
  end

  def connection_finished(connection)
    super(connection)

    if connection.request.env["query_killer"]
      connection.request.env["query_killer"].kill
    end

  end

end

This can be included into thin via command-line arguments:

thin start  -r 'my_module/backend' --backend MyModule::Backend

Upvotes: 1

Related Questions