2012-11-27 31 views
8

chúng tôi có nhu cầu xuất tệp csv bao gồm dữ liệu từ mô hình từ quản trị viên Django chạy trên Heroku. Do đó, chúng tôi đã tạo một hành động mà chúng tôi đã tạo csv và trả lại trong phản hồi. Điều này làm việc tốt cho đến khi khách hàng của chúng tôi bắt đầu xuất dữ liệu khổng lồ và chúng tôi chạy vào thời gian chờ 30 giây của nhân viên Web.Xuất CSV trong luồng (từ quản trị Django trên Heroku)

Để tránh sự cố này, chúng tôi đã nghĩ về việc truyền trực tuyến csv cho ứng dụng khách thay vì xây dựng nó trước tiên trong bộ nhớ và gửi nó thành một phần. Trình kích hoạt là phần thông tin này:

Cedar hỗ trợ phản hồi bỏ phiếu và phát trực tiếp. Ứng dụng của bạn có cửa sổ thứ hai 30 giây đầu tiên để phản hồi bằng một byte đơn trở lại ứng dụng khách. Sau mỗi byte được gửi (hoặc nhận được từ máy khách hoặc được gửi bởi ứng dụng của bạn), bạn thiết lập lại một cửa sổ 55 giây. Nếu không có dữ liệu nào được gửi trong cửa sổ thứ 55 thì kết nối của bạn sẽ bị chấm dứt.

Do đó chúng tôi thực hiện cái gì đó trông như thế này để kiểm tra nó:

import cStringIO as StringIO 
import csv, time 

def csv(request): 
    csvfile = StringIO.StringIO() 
    csvwriter = csv.writer(csvfile) 

def read_and_flush(): 
    csvfile.seek(0) 
    data = csvfile.read() 
    csvfile.seek(0) 
    csvfile.truncate() 
    return data 

def data(): 
    for i in xrange(100000): 
     csvwriter.writerow([i,"a","b","c"]) 
     time.sleep(1) 
     data = read_and_flush() 
     yield data 

response = HttpResponse(data(), mimetype="text/csv") 
response["Content-Disposition"] = "attachment; filename=test.csv" 
return response 

Phần header HTTP của việc tải xuống trông như thế này (từ Firebug):

HTTP/1.1 200 OK 
Cache-Control: max-age=0 
Content-Disposition: attachment; filename=jobentity-job2.csv 
Content-Type: text/csv 
Date: Tue, 27 Nov 2012 13:56:42 GMT 
Expires: Tue, 27 Nov 2012 13:56:41 GMT 
Last-Modified: Tue, 27 Nov 2012 13:56:41 GMT 
Server: gunicorn/0.14.6 
Vary: Cookie 
Transfer-Encoding: chunked 
Connection: keep-alive 

"Chuyển mã hóa : chunked "sẽ chỉ ra rằng Cedar thực sự đang truyền tải nội dung một cách chunkwise chúng tôi đoán.

Vấn đề là việc tải xuống của csv vẫn bị gián đoạn sau 30 giây với những dòng này trong nhật ký Heroku:

2012-11-27T13:00:24+00:00 app[web.1]: DEBUG: exporting tasks in csv-stream for job id: 56, 
2012-11-27T13:00:54+00:00 app[web.1]: 2012-11-27 13:00:54 [2] [CRITICAL] WORKER TIMEOUT (pid:5) 
2012-11-27T13:00:54+00:00 heroku[router]: at=info method=POST path=/admin/jobentity/ host=myapp.herokuapp.com fwd= dyno=web.1 queue=0 wait=0ms connect=2ms service=29480ms status=200 bytes=51092 
2012-11-27T13:00:54+00:00 app[web.1]: 2012-11-27 13:00:54 [2] [CRITICAL] WORKER TIMEOUT (pid:5) 
2012-11-27T13:00:54+00:00 app[web.1]: 2012-11-27 13:00:54 [12] [INFO] Booting worker with pid: 12 

này nên làm việc về mặt khái niệm, phải không? Có bất cứ điều gì chúng tôi bị mất?

Chúng tôi thực sự đánh giá cao sự trợ giúp của bạn. Tom

Trả lời

6

Tôi đã tìm ra giải pháp cho vấn đề. Nó không phải là một thời gian chờ Heroku bởi vì nếu không sẽ có một H12 thời gian chờ trong nhật ký Heroku (nhờ Caio của Heroku để chỉ ra rằng).

Vấn đề là thời gian chờ mặc định của Gunicorn là 30 giây. Sau khi thêm - timeout 600 vào Procfile (ở dòng Gunicorn), vấn đề đã biến mất.

Các Procfile bây giờ trông như thế này:

web: gunicorn myapp.wsgi -b 0.0.0.0:$PORT --timeout 600 
celeryd: python manage.py celeryd -E -B --loglevel=INFO 
0

Đó không phải là vấn đề của tập lệnh của bạn, nhưng vấn đề thời gian chờ yêu cầu web là 30 giây Heroku timeout. Bạn có thể đọc: https://devcenter.heroku.com/articles/request-timeout và theo tài liệu này - di chuyển xuất CSV của bạn sang nền sau.

+0

Nhưng nên cửa sổ 30 timeout thứ hai không thể kéo dài bởi vì chúng tôi dòng nội dung thay vì chờ cho đến khi csv đã được tạo ra trong bộ nhớ? Vì vậy, có các byte được truyền trong cửa sổ 30 giây này và điều này sẽ tránh thời gian chờ theo như sau: Cedar hỗ trợ các tính năng HTTP 1.1 chẳng hạn như phản hồi và phát trực tuyến dài. Một ứng dụng có một cửa sổ ban đầu 30 giây để phản hồi với một byte đơn trở lại máy khách. Tuy nhiên, mỗi byte truyền sau đó đặt lại một cửa sổ 55 giây. – Tom

+0

Có thể nào là Django có thời gian chờ nội bộ khi gửi phản hồi? – Tom

+0

Bạn có yêu cầu web của bạn hoạt động trong hơn 30 giây - đó là sự thật và Heroku có thời gian chờ mặc định là 30 giây đối với bất kỳ yêu cầu web nào trong cấu hình máy chủ http của nó. Tôi cho rằng, những cố gắng của bạn để mô phỏng phiên giao tiếp sẽ không thành công - bạn nên xem xét việc chuyển tệp xử lý dài của mình sang nền/daemon nền. – moonsly

Các vấn đề liên quan