Situation
- upload file from a HTML form with submit button- after submit, processing file take too long and timeout occur
- want to display progress after submit request
Solution 1
- use thread to process request, thus return response immediately- keep progress data in session
- use Ajax to submit and display progress
Drawback
- no progress shown during submit big file
Solution 2
- use submit button to submit request- use thread to process request, thus return response immediately
- keep progress data in session
- redirect to progress page, which use Ajax to display progress
Detail for Solution : use thread to process request
- for uwsgi, enable thread in uwsgi.ini by adding this row
# enable thread
enable-threads=True
- in Django, use code below to create thread
import threading
...
def func():
...
args = [arg1, arg2]
t = threading.Thread(target=do_something, args=args)
t.daemon = True
t.start()
def do_something(arg1, arg2):
...
Detail for Solution : use Ajax to submit form data
- use jQuery Form Plugin to submit form data (especially uploaded file) from ajaxdetail here >> http://jquery.malsup.com/form/#getting-started
detail for available options >> http://jquery.malsup.com/form/#options-object
options = {
type: "POST",
url: "/import_ajax", // target url to submit form data
validate: true,
data: {'validate_question_ajax': '1'}, // additional data to be submitted with other form data
dataType: 'json',
success: function(response, textStatus, jqXHR){
...
// start timer (to display progress) only if request is submitted successfully
init_timer();
},
// callback handler that will be called on error
error: function(jqXHR, textStatus, errorThrown){
...
}
};
$('#MyForm').ajaxSubmit(options);
Detail for Solution : save progress in session
- code below in django to get/set progress in session
// enforce no cache for progress
// redirect to this method from url, e.g. "/import_progress"
@cache_control(no_cache=True)
def get_progress(request):
// use session key in request to get session data
s = SessionStore(session_key=request.session._session_key)
progress = s.get('progress', None)
is_done = s.get('is_done', None)
if is_done:
return JSONResponse({'message': 'done %s records.' % progress, 'detail': s['detail']})
else:
return JSONResponse({'message': 'process %s records.' % progress, })
def set_progress(session_key, progress, detail=None, reset=False):
s = SessionStore(session_key=session_key)
s['progress'] = progress
s['is_done'] = (detail is not None)
if detail:
s['detail'] = detail
elif reset:
s['detail'] = []
s.save()
def do_something(request):
// reset progress data immediately before process request
set_progress(request.session._session_key, 0, reset=True)
Detail for Solution : use Ajax to display progress
- code below in javascript
var progress_timer;
// a function to initialize timer (called later)
function init_timer() {
// set timer to update status of importing Slam history
progress_timer = setInterval(function() {
$.ajax({
url: "/import_progress", // url that return progress data, redirect to method get_progress() above
...
success: function(response, textStatus, jqXHR){
// output progress
$("#import_progress").html(response.message);
if (response.is_done != null) {
// stop timer when process completed
clearInterval(progress_timer);
}
// emergency braker
i += 1;
if (i > 1000) {
clearInterval(progress_timer);
}
},
...
});
}, 5000); // timer interval in millisec
}
...
// pass this as ajax submit option
// this will be returned immediately after worker thread started
success: function(response, textStatus, jqXHR){
if (response.error != null) {
...
}
else {
// if worker thread started normally, start timer to display progress
init_timer();
}
},
Detail Solution : HTML page to show progress
- code below in javascript to initialize timer when loaded page
$(function() {
jQuery(document).ready(function(e) {
init_timer(); // same function as above
});
});
ไม่มีความคิดเห็น:
แสดงความคิดเห็น