我可以将 http 流与 axlsx_rails 一起使用以避免 large/time 密集查询的超时问题吗?
Can I use http streaming with axlsx_rails to avoid timeout issue with large/time intensive query?
我正在使用 Rails 4.2.5 中的 axlsx_rails Ruby gem 生成一个 Excel 文件让用户下载他们的数据。
我的 index.xlsx.axlsx 模板中有这个:
wb = xlsx_package.workbook
wb.add_worksheet(name: 'Transactions') do |sheet|
sheet.add_row ["Date", "Vendor Name", "Account",
"Transaction Category",
"Amount Spent", "Description"]
@transactions.find_each(batch_size: 100) do |transaction|
sheet.add_row [transaction.transaction_date,
transaction.vendor_name,
transaction.account.account_name,
transaction.transaction_category.name,
transaction.amount,
transaction.description]
end
end
如果有足够的数据,页面在返回 Excel 文件之前超时。有没有办法在处理过程中使用 HTTP 流发送回结果,而不是等到整个 transactions.find_each 循环完成?
我看到代码 here 使用 response.stream.write:
response.headers['Content-Type'] = 'text/event-stream'
10.times {
response.stream.write "This is a test message"
sleep 1
}
response.stream.close
这种方法看起来很有希望,但我不知道如何将 response.stream.write 集成到 axlsx_rails 模板中。有办法吗?
这是我的第一个 Stack Overflow 问题 - 对任何失礼表示歉意,并感谢您提供的任何想法。
欢迎来到 SO,乔。
我在评论中问过,但也许最好回答并解释一下。
简短的回答是,是的,如果可以渲染,则始终可以进行流式传输(尽管有时性能结果参差不齐)。
但是,如果您直接引用文件,它就不起作用。即,http://someurl.com/reports/mycustomreport.xlsx
rails 中的流式传输并不是默认情况下构建的。但不用担心,您 "should" 仍然可以解决您的问题,前提是您希望节省的时间仅用于渲染。
在您的控制器中(* 以后请注意,当您询问渲染操作时,提供您的控制器操作代码会有所帮助 *)您应该能够执行类似于以下操作的操作:
def report
@transactions = current_user.transactions.all
respond_to do |format|
format.html { render xlsx: 'report', stream: true}
end
end
可能有助于对您的加载进行完整性检查。在您的日志中,作为 200 响应的一部分,您应该得到如下内容:
在 506 毫秒内完成 200 OK(视图:494.6 毫秒 | ActiveRecord:2.8 毫秒)
如果活动记录数太高,或高于视图数,此解决方案可能不适用于您的查询,并且按照建议,这可能需要线程化或发送到作业。
即使可以直播,我也不认为会更快。问题是 Axlsx 在您完成构建之前不会生成您的电子表格。而 axlsx_rails 只是包装了这个过程,所以它也无济于事。因此,不会有部分电子表格以位形式提供服务,延迟也会一样长。
您应该硬着头皮尝试 Sidekiq(非常快)或其他一些作业调度程序。然后您可以立即 return 请求并在后台生成电子表格。您将必须进行某种监视或通知以获取生成的报告,或者使用 javascript ping 回另一个 url,当在呈现完成时设置标志时转发到新页面。你的电话那里。
当您需要发送电子邮件以响应请求时,拥有作业调度程序也非常方便;响应可以 return 立即而不是等待电子邮件完成。有了调度程序后,您会发现它的更多用途。
如果您选择作业调度程序,axlsx_rails 会让您 use your template to generate the attachment, or you can create your own view context to generate the file. Or for a really bare bones way of rendering the template, see this test。
我正在使用 Rails 4.2.5 中的 axlsx_rails Ruby gem 生成一个 Excel 文件让用户下载他们的数据。
我的 index.xlsx.axlsx 模板中有这个:
wb = xlsx_package.workbook
wb.add_worksheet(name: 'Transactions') do |sheet|
sheet.add_row ["Date", "Vendor Name", "Account",
"Transaction Category",
"Amount Spent", "Description"]
@transactions.find_each(batch_size: 100) do |transaction|
sheet.add_row [transaction.transaction_date,
transaction.vendor_name,
transaction.account.account_name,
transaction.transaction_category.name,
transaction.amount,
transaction.description]
end
end
如果有足够的数据,页面在返回 Excel 文件之前超时。有没有办法在处理过程中使用 HTTP 流发送回结果,而不是等到整个 transactions.find_each 循环完成?
我看到代码 here 使用 response.stream.write:
response.headers['Content-Type'] = 'text/event-stream'
10.times {
response.stream.write "This is a test message"
sleep 1
}
response.stream.close
这种方法看起来很有希望,但我不知道如何将 response.stream.write 集成到 axlsx_rails 模板中。有办法吗?
这是我的第一个 Stack Overflow 问题 - 对任何失礼表示歉意,并感谢您提供的任何想法。
欢迎来到 SO,乔。
我在评论中问过,但也许最好回答并解释一下。
简短的回答是,是的,如果可以渲染,则始终可以进行流式传输(尽管有时性能结果参差不齐)。
但是,如果您直接引用文件,它就不起作用。即,http://someurl.com/reports/mycustomreport.xlsx
rails 中的流式传输并不是默认情况下构建的。但不用担心,您 "should" 仍然可以解决您的问题,前提是您希望节省的时间仅用于渲染。
在您的控制器中(* 以后请注意,当您询问渲染操作时,提供您的控制器操作代码会有所帮助 *)您应该能够执行类似于以下操作的操作:
def report
@transactions = current_user.transactions.all
respond_to do |format|
format.html { render xlsx: 'report', stream: true}
end
end
可能有助于对您的加载进行完整性检查。在您的日志中,作为 200 响应的一部分,您应该得到如下内容:
在 506 毫秒内完成 200 OK(视图:494.6 毫秒 | ActiveRecord:2.8 毫秒)
如果活动记录数太高,或高于视图数,此解决方案可能不适用于您的查询,并且按照建议,这可能需要线程化或发送到作业。
即使可以直播,我也不认为会更快。问题是 Axlsx 在您完成构建之前不会生成您的电子表格。而 axlsx_rails 只是包装了这个过程,所以它也无济于事。因此,不会有部分电子表格以位形式提供服务,延迟也会一样长。
您应该硬着头皮尝试 Sidekiq(非常快)或其他一些作业调度程序。然后您可以立即 return 请求并在后台生成电子表格。您将必须进行某种监视或通知以获取生成的报告,或者使用 javascript ping 回另一个 url,当在呈现完成时设置标志时转发到新页面。你的电话那里。
当您需要发送电子邮件以响应请求时,拥有作业调度程序也非常方便;响应可以 return 立即而不是等待电子邮件完成。有了调度程序后,您会发现它的更多用途。
如果您选择作业调度程序,axlsx_rails 会让您 use your template to generate the attachment, or you can create your own view context to generate the file. Or for a really bare bones way of rendering the template, see this test。