2017-10-18 12 views
1

제공된 사용자의 많은 레코드를 데이터베이스로 가져 오는 것과 관련된 문제가 있습니다. 이 논리는 잘 작동하고 있으며 ActiveRecord 가져 오기를 사용하여 데이터베이스 호출 수를 줄였습니다. 그러나 파일이 너무 크면 처리 시간이 오래 걸리고 Heroku가 시간 초과를 반환합니다. 해결 방법 : 처리를 백그라운드 작업으로 다시 조정하고 이동합니다.Rails + 백그라운드 작업 가져 오기에서 데이터베이스에 아무 것도 추가하지 않음

지금까지 그렇게 좋았습니다. 백그라운드 작업을 위해 메모리에 파일을 보관할 수 없기 때문에 CarrierWave를 추가하여 S3에 파일을 업로드해야했습니다. 업로드 부분도 잘 작동하고 있습니다. 모델을 만들었고 대기중인 작업에 ID를 전달하여 나중에 전체 ActiveRecord 객체를 전달할 수 없다는 것을 알기 때문에 파일을 검색합니다.

Resque 및 Redis를 로컬에 설치 했으므로 모든 점이 올바르게 설정되어있는 것으로 보입니다. 내가 만들고있는 작업을 대기열에 넣은 다음 실패없이 실행할 수 있습니다. 작업이 정상적으로 실행되는 것으로 보이지만 데이터베이스에 레코드가 추가되지 않습니다. 내 작업 코드를 콘솔에서 줄 단위로 실행하면 예상대로 데이터베이스에 레코드가 추가됩니다. 그러나 내가 만든 대기중인 작업이 실행되면 아무 일도 일어나지 않습니다.

문제가있는 부분을 잘 풀 수 없습니다.

여기 내 업로드 컨트롤러의 생성 작업입니다 :

def create 
    @upload = Upload.new(upload_params) 
    if @upload.save 
    Resque.enqueue(ExcelImportJob, @upload.id) 
    flash[:info] = 'File uploaded. 
     Data will be processed and added to the database.' 
    redirect_to root_path 
    else 
    flash[:warning] = 'Upload failed. Please try again.' 
    render :new 
    end 
end 

이 명확성을 위해 적은 시트 열 작업의 단순화 된 버전입니다 :

class ExcelImportJob < ApplicationJob 
    @queue = :default 

    def perform(upload_id) 
    file = Upload.find(upload_id).file.file.file 
    data = parse_excel(file) 
    if header_matches? data 
     # Create a database entry for each row, ignoring the first header row 
     # using activerecord-import 
     sales = [] 
     data.drop(1).each_with_index do |row, index| 
     sales << Sale.new(row) 
     if index % 2500 == 0 
      Sale.import sales 
      sales = [] 
     end 
     end 
     Sale.import sales 
    end 

    def parse_excel(upload) 
     # Open the uploaded excel document 
     doc = Creek::Book.new upload 

     # Map rows to the hash keys from the database 
     doc.sheets.first.rows.map do |row| 
     { date: row.values[0], 
      title: row.values[1], 
      author: row.values[2], 
      isbn: row.values[3], 
      release_date: row.values[5], 
      units_sold: row.values[6], 
      units_refunded: row.values[7], 
      net_units_sold: row.values[8], 
      payment_amount: row.values[9], 
      payment_amount_currency: row.values[10] } 
     end 
    end 

    # Returns true if header matches the expected format 
    def header_matches?(data) 
     data.first == {:date => 'Date', 
        :title => 'Title', 
        :author => 'Author', 
        :isbn => 'ISBN', 
        :release_date => 'Release Date', 
        :units_sold => 'Units Sold', 
        :units_refunded => 'Units Refunded', 
        :net_units_sold => 'Net Units Sold', 
        :payment_amount => 'Payment Amount', 
        :payment_amount_currency => 'Payment Amount Currency'} 
    end 
    end 
end 

내가 아마 권리로 어쨌든 몇 가지 개선 된 논리를 가질 수 있습니다 지금은 전체 파일을 메모리에 보유하고 있지만, 문제는 아닙니다. 500 개 정도의 작은 행을 가진 작은 파일이라도 작업은 데이터베이스에 아무 것도 추가하지 않습니다.

마찬가지로 백그라운드 작업을 사용하지 않을 때 내 코드가 정상적으로 작동하고 콘솔에서 실행하면 작동한다고합니다. 그러나 웬일인지 그 일은 아무것도하지 않고있다.

Resque를 처음 사용하는 이유는 무엇인지 확실하지 않습니다. 나는 노동자를 만들었고 내가 말했듯이 그 일을하는 것처럼 보입니다.

*** resque-1.27.4: Waiting for default 
*** Checking default 
*** Found job on default 
*** resque-1.27.4: Processing default since 1508342426 [ExcelImportJob] 
*** got: (Job{default} | ExcelImportJob | [15]) 
*** Running before_fork hooks with [(Job{default} | ExcelImportJob | [15])] 
*** resque-1.27.4: Forked 63706 at 1508342426 
*** Running after_fork hooks with [(Job{default} | ExcelImportJob | [15])] 
*** done: (Job{default} | ExcelImportJob | [15]) 

실패로 일자리가 기록되지 않은 Resque 대시 보드에서 : 여기 Resque의 자세한 포맷의 출력이다. 그들은 실행되고 통계 페이지에서 '처리 된'작업의 증가를 볼 수 있습니다. 하지만 DB에 아무런 영향을 미치지 않습니다. 무슨 일이야? 어떻게하면 작업을 더 명확하게 디버그 할 수 있습니까? Pry와 함께 들어갈 수있는 방법이 있습니까?

+0

'Sale.import sales'를 호출하기 전에'sales.count'를 로깅하여 데이터로'import' 호출을하는지 확인할 수 있습니까? – hoffm

+0

좋은 생각입니다. 나는 Resque에 정말로 새롭다. Resque 로그에 인쇄 할 수있는 방법이 있습니까? 그 문법은 무엇입니까? 방금'logger.info '를 사용하여 # {sales.count} 판매를 수집 했나요? "그런가요? –

+0

출력을 stdout으로 보내면 결과를 볼 수 있다고 생각합니다. 그래서 수집 된 # {sales.count} 판매량을 가져 오면 "트릭을해야합니다. Resque worker를'rake resque : work'로 시작한다고 가정합니까? – hoffm

답변

1

내 문제가 Resque.enqueue(ExcelImportJob, @upload.id) 인 것처럼 보입니다.

내 코드가 ExcelImportJob.perform_later(@upload.id)으로 변경되었으므로 실제로 코드가 실행됩니다.

여기에 설명 된대로 resque.rake 작업을 lib/tasks에 추가했습니다. http://bica.co/2015/01/20/active-job-resque/.

이 링크는 rails runner을 사용하여 전체 Rails 서버를 실행하지 않고 작업을 호출하고 디버깅에 유용한 작업을 트리거하는 방법에 대해서도 설명합니다.

이상하게도, 나는 @hoffm이 제안한 것처럼 STDOUT에 아무 것도 인쇄하지 못했지만, 적어도 그것은 좋은 질문을 이끌었다.

여전히 Resqueue.enqueue를 호출하여 대기열에 내 작업이 추가되어 실제로 실행되는 것처럼 보이지만 실제로 코드가 실행되지 않은 이유와 다른 점이 무엇인지에 대해 아직 완전히 이해하지 못하고 있습니다. 설명, 그게 많이 감사하겠습니다.

TL : DR : Resque.enqueue이 아닌 고정 전화 번호 perform_later이 문제를 해결했지만 이유를 모르겠습니다.