Что-то делать, когда пользователь прерывает соединение (Sinatra + Thin)

Я пишу приложение, которое иногда требует очень длительных запросов к БД. Я хотел бы выполнить некоторый код, если клиент перезагружает или закрывает страницу, чтобы делать что-то с запросами БД.

Я надеялся, что у Рэка будут какие-то крючки в этом роде, но, судя по тому, что я видел, это уровень глубже, чем у Рэка.

Пока единственный способ, который я могу найти, заключается в самом тонком, путем исправления обезьяной функции unbind в тонком классе Connection:

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

Это переопределяет функцию развязки Thin и позволяет мне подключаться к отключению, вызываемому EventMachine.

Есть ли способ лучше?


person Ben    schedule 08.12.2011    source источник
comment
Вам следует рассмотреть возможность асинхронного выполнения длительных запросов. Это был бы более чистый дизайн, а также решил бы вашу нынешнюю проблему.   -  person randomuser    schedule 08.12.2011
comment
На самом деле я запускаю запрос асинхронно, используя EventMachine, em-syncrhony и sinatra-synchrony. Это все еще не решает мою проблему - я хочу знать, когда пользователь перестает заботиться о результатах из БД, независимо от того, является ли запрос синхронным.   -  person Ben    schedule 08.12.2011
comment
Насколько я понимаю, sinatra-synchrony запускает только запросы одновременно. Поэтому я все еще думаю, что совет @Gunjan применим.   -  person Paulo Casaretto    schedule 13.12.2011
comment
Как я упоминал ранее, моя проблема не имеет ничего общего с тем, является ли запрос синхронным. Проблема в том, что некоторые из запросов к базе данных настолько массивны, что могут сделать базу данных бесполезной, и мне нужно иметь возможность убить их, если пользователь покинет страницу. Эта проблема существует независимо от того, выполняется ли запрос базы данных асинхронно.   -  person Ben    schedule 25.12.2011
comment
Вы можете использовать метод async_close выше. В качестве примера взгляните на Sinatra::ExtendedRack #setup_close   -  person Andrea Amantini    schedule 29.03.2015
comment
Если вы используете Sinatra::Helpers::Streaming ответ, вы можете настроить обратные вызовы, которые вызываются (откладываются) при указанном выше вызове async_close. Это удобно, чтобы сделать некоторую очистку, когда клиент отключается (например, EventSource#close на стороне javascripts)   -  person Andrea Amantini    schedule 29.03.2015


Ответы (1)


После некоторого копания я обнаружил, что Thin предоставляет механизм для замены «бэкенда» или того, как сервер подключается к клиенту. Я использую это в сочетании со значениями в стойке env для обработки конкретных экземпляров запроса и знаю, нужно ли мне убивать запрос или нет:

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

Это может быть включено в тонкий с помощью аргументов командной строки:

thin start  -r 'my_module/backend' --backend MyModule::Backend
person Ben    schedule 24.12.2011