Rails: обновить контроллер с результатом sidekiq

Доброе утро!

У меня есть форма, которая принимает IP-адрес, дату начала и дату окончания, которая вызывает рабочий процесс SideKiq, который выполняет скрипт на внешнем сервере через ssh, а затем отправляет полученный файл на локальный сервер по протоколу sFTP.

Метод контроллера:

def create
  @script = Script.new(params[:script])
  if @script.valid?
    @job_id = LogsWorker.perform_async(@script.ip, @script.start_date, @script.stop_date)
  else
    render :action => 'new'
  end
end

Рабочий SideKiq:

def perform(ip, start_date, stop_date)
  Net::SSH.start('server', 'username') do |ssh|
    result = ssh.exec!("<script here> #{ip} #{start_date} #{stop_date}")
    ssh.sftp.connect do |sftp|
      local_result = "#{Rails.root}/public/uploads/" + File.basename(result)
      sftp.download!(result, local_result)
    end
  end
    .. to be continued ..

У меня также есть рабочий процесс SideKiq, который анализирует полученный файл в хэш:

  .. continuing ..
  @file_hash = {}
  i = 0
  File.open(local_result, "r") do |fp|
    fp.each_line do |line|
      ip, date, method, url_full = line.split("\t")
      @file_hash[i] = {ip: ip, date: date, method: method, url_full: url_full}
      i += 1
    end
  end
end

И частичный _results.html.erb, который его анализирует:

<% if @file_hash %>
  <% @file_hash.each do |key, value| %>
    <tr>
      <td><%= value[:ip] %></td>
      <td><%= value[:date] %></td>
      <td><%= value[:method] %></td>
      <td><%= value[:url_full] %></td>
    </tr>
  <% end %>
<% end %>

Я попытался отобразить результаты после завершения задания с помощью <%= render partial: 'results', locals: { file_hash: @file_hash } %> в файле create.js.coffee, но я не думаю, что он имеет какое-либо представление о переменной экземпляра.

Как я могу передать результат из заполненной переменной SideKiq в представление? Я думаю, я должен отметить, что у меня есть другой метод контроллера, который запрашивает процент выполнения задания SideKiq, поэтому я должен быть в состоянии определить, когда оно будет завершено.

Редактировать:

percentage_done в контроллере

def percentage_done
  job_id = params[:job_id] # grabbing the job_id from params

  container = SidekiqStatus::Container.load(job_id)

  @pct_complete = container.pct_complete

  respond_to do |format|
    format.json {
      render :json => {
        :percentage_done => @pct_complete, # responding with json with the percent complete data
      }
    }
  end
end

текущий аякс

queryForPercentage = () ->
  job_id = $('#job_id').text() # grabbing the job_id
  $.ajax({
    url: "/percentage_done" # sending an ajax request to /percentage_done
    data: job_id: job_id # using the job_id from the DOM
    success: (data) -> # executed after a successful call to the percentage_done controller
      percentage = 'width: ' + data['percentage_done'] + '%;'
      # writing the percentage done to the progress bar
      $('#job-progress').attr('style', percentage).text(data['percentage_done'] + '%')
      $('#job-progress').attr('aria-valuenow', data['percentage_done'])

      if $('#job-progress').text() != '100%'
        setTimeout((-> queryForPercentage()), 1500)
      else
        # replace the html of the div script_lists with the updated new one
        $("#scripts_list").html("<%= escape_javascript(render partial: 'results', locals: { file_hash: @file_hash } ) %>");
  })

queryForPercentage()

person aplewandowski    schedule 27.06.2014    source источник
comment
Я просто хотел напечатать несколько сообщений от sidekiq в своих представлениях, и для этого мне пришлось использовать faye gem. Так что я думаю, что это не так просто.   -  person alexsmn    schedule 27.06.2014
comment
Вы разобрались с этим? Я хочу сделать то же самое.   -  person stephenmurdoch    schedule 02.12.2014


Ответы (1)


Sidekiq используется для обработки фоновых заданий. IMO, отправляющая результат задания Sidekiq обратно в представление, противоречит цели использования Sidekiq; почему бы просто не выполнить задание в том же запросе.

С учетом сказанного вы можете выполнить это с помощью AJAX-вызова представления, которое опрашивает контроллер, запрашивающий Sidekiq для завершения. Этот контроллер также может возвращать содержимое файла. Если работа Sidekiq не займет слишком много времени, это может быть неплохим пользовательским опытом.

person kcdragon    schedule 27.06.2014
comment
Это длительный процесс... обычно от 5 секунд до 10+ минут, хотя, как правило, в диапазоне 30 секунд или 3-5 минут. Я использую метод процента_done (действие? Извините, новичок в рельсах), который отслеживает его завершение. Есть ли способ передать полученное имя файла другому действию и обновить это представление? - person aplewandowski; 27.06.2014
comment
Как насчет того, чтобы указать имя файла, а затем передать это имя рабочему процессу Sidekiq? - person kcdragon; 27.06.2014
comment
Я добавил свой текущий метод контроллера и ajax, который я использую, к вопросу. - person aplewandowski; 27.06.2014
comment
Я не могу придумать способ получить имя файла из задания Sidekiq в том же запросе. Я бы передал имя файла в задание Sidekiq, и тогда вы узнаете, где находится файл. - person kcdragon; 27.06.2014
comment
Имя файла фактически определяется в рамках задания Sidekiq. local_result = "#{Rails.root}/public/uploads/" + File.basename(result). Есть ли простой способ использовать ajax для рендеринга нового действия и отображения частичного с соответствующей переменной экземпляра? На самом деле это даже не обязательно должна быть переменная экземпляра. - person aplewandowski; 27.06.2014
comment
У меня такое чувство, что я собираюсь в конечном итоге ответить на свой собственный вопрос, но спасибо, что развлекли его. Я думаю, что меня больше всего смущает, как это сделать с помощью ajax, а не обычным способом. - person aplewandowski; 27.06.2014
comment
Вы можете сохранить имя файла в базе данных, а затем запросить его на основе идентификатора задания. Имя файла может быть возвращено в том же вызове AJAX для выполнения. - person kcdragon; 27.06.2014