제공된 사용자의 많은 레코드를 데이터베이스로 가져 오는 것과 관련된 문제가 있습니다. 이 논리는 잘 작동하고 있으며 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와 함께 들어갈 수있는 방법이 있습니까?
'Sale.import sales'를 호출하기 전에'sales.count'를 로깅하여 데이터로'import' 호출을하는지 확인할 수 있습니까? – hoffm
좋은 생각입니다. 나는 Resque에 정말로 새롭다. Resque 로그에 인쇄 할 수있는 방법이 있습니까? 그 문법은 무엇입니까? 방금'logger.info '를 사용하여 # {sales.count} 판매를 수집 했나요? "그런가요? –
출력을 stdout으로 보내면 결과를 볼 수 있다고 생각합니다. 그래서 수집 된 # {sales.count} 판매량을 가져 오면 "트릭을해야합니다. Resque worker를'rake resque : work'로 시작한다고 가정합니까? – hoffm