Reputation: 11
I'm using django development server on windows 8.1 64 bit. I'm also using Tastypie. The mysql version is: 5.5 (x86).
The problem I'm facing is that various queries randomly hangs. I'm using AJAX at the client, but it also happens when I'm using the django admin. I saw that all similar questions relates to chrome issue. But it happens also on Firefox. My database is mysql. Lately I installed SSD drive so all my development code and database is on that SSD (not that I think this should make any difference)
Here is an example of few queries as seen in the Firebug. in this case the 4th hangs (randomly, sometimes it is a different one)
GET id=1">http://127.0.0.1:8000/api/v1/financialmodel/?user_id=1 200 OK 1.33s jquery....min.js GET id=1">http://127.0.0.1:8000/api/v1/strategy/?user_id=1 200 OK 1.35s jquery....min.js (line 6) GET id=1">http://127.0.0.1:8000/api/v1/currency/?user_id=1 200 OK 1.4s jquery....min.js (line 6) the next query get stuck (but this is random sometime it is another query) GET id=1">http://127.0.0.1:8000/api/v1/account/?user_id=1 jquery....min.js (line 6) GET id=1">http://127.0.0.1:8000/api/v1/bankbranch/?user_id=1 200 OK 2.62s
I tried running the server with:
runserver with --nothread (or without)
did not change anything.
I tried installing //github.com/ashchristopher/django-concurrent-server thinking this might help, but same thing still random hangs on various queries.
If I pause the server using the debugger in the APTANA IDE, I find that the server is at:
SocketServer.py line 155
def _eintr_retry(func, *args):
"""restart a system call interrupted by EINTR"""
while True:
try:
return func(*args)
except (OSError, select.error) as e:
if e.args[0] != errno.EINTR:
raise
Any ideas? Thanks a lot!
Here is the line in the Ajax code from jquery-2.0.3
// Do send the request
// This may raise an exception which is actually
// handled in jQuery.ajax (so no try/catch here)
xhr.send( options.hasContent &&
options.data || null );
},
abort: function() {
if ( callback ) {
callback();
}
}
};
}
});
Here is a function that loads a ui tree:
function loadAccountsTree() {
$.getJSON("/api/v1/account/?user__id=" + userid, function(json) {
// Extracting the required JSON structure from the entire response
var tree = json.objects[0];
$("#accounts-tree").jstree({
"sort" : function() {
},
"json_data" : {
"data" : tree
},
"types" : {
"max_children" : 1,
"types" : {
// Account type
"default" : {
"valid_children" : "none"
},
"folder" : {
"valid_children" : ["default", "folder"]
}
}
},
"hotkeys" : {
"return" : function() {
var hovered = $('#accounts-tree .jstree-hovered');
if (hovered.length) {
$("#accounts-tree").jstree("deselect_all");
$("#accounts-tree").jstree("select_node", hovered);
}
}
},
"ui" : {
select_multiple_modifier : false
},
"contextmenu" : {
// Select node when right-clicking
"select_node" : true,
items : {// Could be a function that should return an object like this one
"ccp" : false,
"create" : {
"separator_before" : false,
"separator_after" : true,
"label" : "Create",
"action" : false,
"submenu" : {
"create_file" : {
"seperator_before" : false,
"seperator_after" : false,
"label" : "Account",
action : function(obj) {
this.create(obj, "last", {
"attr" : {
"rel" : "default"
}
});
}
},
"create_folder" : {
"seperator_before" : false,
"seperator_after" : false,
"label" : "Folder",
action : function(obj) {
this.create(obj, "last", {
"attr" : {
"rel" : "folder"
}
});
}
} // End of "create_folder" contextmenu function
}
}
}
},
"plugins" : ["themes", "json_data", "ui", "hotkeys", "crrm", "dnd", "contextmenu", "types"]
}).bind("before.jstree", function(e, data) {
if (data.func === "remove") {
var nodes = data.inst._get_node(null, true);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
var nodeName = $(node).find('> a').text().substring(1);
if ($(node).find('> ul').length) {
alert('You need to delete all folders and accounts inside ' + nodeName + ' before deleting it.');
e.stopImmediatePropagation();
return false;
} else if (!confirm("Are you sure you want to delete " + nodeName + " ?")) {
e.stopImmediatePropagation();
return false;
}
}
}
}).bind("loaded.jstree", function(event, data) {
// Selecting top account
data.inst.select_node('> ul > li:first');
// Loading all assets for top account
loadAccountAssets($("#accounts-tree > ul:first > li:first").attr("id"));
loadCommissions($("#accounts-tree > ul:first > li:first").attr("id"));
}).bind("create.jstree", function(e, data) {
var newNode = data.rslt.obj;
var verified = true;
$(newNode).siblings().each(function(idx, listItem) {
var siblingNode = $(listItem);
if (newNode.attr("rel") !== siblingNode.attr("rel")) {
verified = false;
return false;
}
});
var isFolder;
if (data.rslt.obj.attr("rel") == 'default') {
isFolder = 'false';
} else {
isFolder = 'true';
}
if (verified) {
$.ajax({
type : 'POST',
// make sure you respect the same origin policy with this url:
// http://en.wikipedia.org/wiki/Same_origin_policy
url : '/api/v1/account/',
data : JSON.stringify({
'folder' : isFolder,
'user' : '/api/v1/user/' + userid + '/',
'parent' : '/api/v1/account/' + data.rslt.parent.attr("id") + '/',
'name' : data.rslt.name,
'type' : data.rslt.obj.attr("rel")
}),
contentType : "application/json",
dataType : 'json',
processData : false,
success : function(r) {
data.rslt.obj.attr("id", r.id);
},
error : function(xhr, textStatus, error) {
loadAccountsTree();
logErrors(xhr, textStatus, error);
}
});
} else {
alert("Folders can contain either folders or accounts, not both at a time.");
$(newNode).prev().addClass("jstree-last");
$(newNode).remove();
}
}).bind("rename.jstree", function(e, data) {
$.ajax({
type : 'PATCH',
url : '/api/v1/account/' + data.rslt.obj.attr("id") + '/',
data : JSON.stringify({
"name" : data.rslt.new_name
}),
dataType : 'json',
contentType : 'application/json',
error : function(xhr, textStatus, error) {
loadAccountsTree();
logErrors(xhr, textStatus, error);
}
});
}).bind("remove.jstree", function(e, data) {
$.ajax({
type : 'DELETE',
url : '/api/v1/account/' + data.rslt.obj.attr("id") + '/'
});
}).bind("select_node.jstree", function(event, data) {
var currentNode = data.rslt.obj;
var ui_currency = ($('#usd').hasClass('active')) ? 'usd' : 'ils';
var isFolder = currentNode.attr("rel") === "folder";
if (isFolder) {
$("#account-form").slideUp();
} else {
// The account is not a folder. Show account details and load its commissions.
$("#account-form").slideDown();
$("#account-name").attr("value", $(currentNode).text().substring(2));
var bankId = $(currentNode).closest("li").data("bank_id");
var accountBank = (bankId) ? bankId : "None";
$("#bank").val(accountBank);
$("#account-type").val($(currentNode).closest("li").data("account_type"));
reloadAccountCommissions(currentNode.attr("id"));
}
reloadAccountAssets(isFolder, currentNode.attr("id"), ui_currency);
var parents = currentNode.parents("li");
var parentsList = currentNode.children("a").text().substring(1);
parents.each(function(index) {
parentsList = $(this).children("a").text().substring(1) + ' > ' + parentsList;
});
$("#account-title").text(currentNode.find("> a").text().substring(1) + " details");
$("#account-breadcrumbs > p").text("Accounts: " + parentsList);
}).bind("move_node.jstree", function(e, data) {
data.rslt.o.each(function(i) {
var valid = true;
var currentNode = $(this);
$(currentNode).siblings().each(function(idx, listItem) {
var siblingNode = $(listItem);
if (currentNode.attr("rel") !== siblingNode.attr("rel")) {
valid = false;
return false;
}
});
if (valid) {
$.ajax({
type : 'PATCH',
url : '/api/v1/account/' + currentNode.attr("id") + '/',
data : JSON.stringify({
"parent" : '/api/v1/account/' + data.rslt.np.attr("id") + '/'
}),
dataType : 'json',
contentType : 'application/json',
error : function(xhr, textStatus, error) {
loadAccountsTree();
logErrors(xhr, textStatus, error);
}
});
} else {
$(data.rslt.op).append(currentNode);
$(currentNode).addClass("jstree-last");
alert("The parent folder can not contain folders and accounts at the same time.");
}
});
});
});
}
Here is the function that loads all the assets for the selected account into a grid (this grid sometimes stays "Loading...", when I check the server log 200 was sent back, but in the Firebug one of the queries never ends
function loadAccountAssets(accountid) {
$("#pager-account-assets").empty();
var ui_currency = ($('#usd').hasClass('active')) ? 'usd' : 'ils';
$("#jqgrid-account-assets").empty().jqGrid({
url : '/api/v1/assetgrid/?user__id=' + userid + '&account__id__in=' + accountid + '&ui_currency_code=' + ui_currency,
datatype : 'json',
ajaxGridOptions : {
contentType : "application/json"
},
jsonReader : {
repeatitems : false,
id : "id"
},
colNames : ['Account', 'Place', 'Subtype', 'Issuer', 'Price linkage', 'Interest type', 'Return net', 'Return gross', 'Maturity term', 'Maturity date', 'Symbol', 'Update', 'Update hint', 'Value', 'Currency', 'Units', 'Price', 'Description', 'FinancialModel'],
// 'Issuer', 'Price linkage', 'Interest type', 'Return net', 'Return gross', 'Maturity term', 'Maturity date', 'Financialmodel',
colModel : [{
name : 'Account',
edittype : 'select',
editoptions : {
dataUrl : '/api/v1/account/?user__id=' + userid + '&folder=false',
buildSelect : function(data) {
var response = $.parseJSON(data);
var s = '<select>';
$.each(response.objects, function(index, account) {
s += '<option value="' + account.resource_uri + '">' + account.data + '</option>';
});
return s + "</select>";
}
},
stype : 'select'
}, buildHiddenColumn('Place', 'place', true, false, 'resource_uri', 'name'), buildHiddenColumn('Subtype', 'subtype', true, false, 'resource_uri', 'name'), buildHiddenColumn('Issuer', 'issuer', true, false, 'resource_uri', 'name'), {
name : 'price_linkage',
hidden : true,
editable : true,
edittype : 'select',
editoptions : {
value : 'F:Foreign Currency;M:Madad;I:ILS'
},
stype : 'select',
editrules : {
edithidden : true
}
}, {
name : 'Interest',
hidden : true,
editable : true,
edittype : 'select',
editoptions : {
value : 'F:Fix;C:Changing;O:Other'
},
stype : 'select',
editrules : {
edithidden : true
}
}, {
name : 'Return Net',
editable : true,
editrules : {
edithidden : true
},
hidden : true,
editoptions : {
dataInit : function(element) {
$(element).attr("readonly", true);
}
}
}, {
name : 'Return Gross',
editable : true,
editrules : {
edithidden : true
},
hidden : true,
editoptions : {
dataInit : function(element) {
$(element).attr("readonly", "readonly");
}
}
}, {
name : 'Maturity',
hidden : true,
editable : true,
edittype : 'select',
editoptions : {
value : 'S:Short;M:Medium;L:Long'
},
stype : 'select',
editrules : {
edithidden : true
}
}, {
name : 'MaturityDate',
hidden : true,
editable : true,
formatter : "date",
editoptions : {
dataInit : function(el) {
setTimeout(function() {
$(el).datepicker({
dateFormat : "yy-mm-dd"
});
}, 200);
}
},
formoptions : {
rowpos : 1,
colpos : 2
},
formatoptions : {
newformat : "Y-m-d"
},
editrules : {
edithidden : true
}
}, symbolColumn, {
name : 'Update',
edittype : 'select',
editoptions : {
value : 'A:Automatic;M:Manual'
},
formoptions : {
rowpos : 2,
colpos : 2
},
stype : 'select',
}, {
name : 'UpdHint',
formoptions : {
rowpos : 3,
colpos : 2
}
}, {
name : 'Value',
width : 70,
editable : false
}, currencyColumn, {
name : 'Units',
width : 70,
formoptions : {
rowpos : 4,
colpos : 2
},
editoptions : {
dataInit : function(elem) {
setTimeout(function() {
// It must be an integer
$(elem).numeric(false, function() {
alert("Integers only");
this.value = "";
this.focus();
});
}, 100);
}
}
}, {
name : 'Price',
width : 70,
formoptions : {
rowpos : 5,
colpos : 2
},
editoptions : {
dataInit : function(elem) {
setTimeout(function() {
$(elem).numeric();
}, 100);
}
}
}, {
name : 'Description',
formoptions : {
rowpos : 6,
colpos : 2
},
width : 200
}, {
name : 'FinancialModel',
edittype : 'select',
formoptions : {
rowpos : 7,
colpos : 2
},
editoptions : {
dataUrl : '/api/v1/financialmodel/?user__id=' + userid,
buildSelect : function(data) {
var response = $.parseJSON(data);
var s = '<select><option value="">None</option>';
$.each(response.objects, function(index, financialmodel) {
s += '<option value="' + financialmodel.resource_uri + '">' + financialmodel.data + '</option>';
});
return s + "</select>";
}
},
stype : 'select'
}],
cmTemplate : {
editable : true,
width : 100
},
ondblClickRow : function() {
var rowid = $("#jqgrid-account-assets").getGridParam('selrow');
$('#jqgrid-account-assets').jqGrid('editRow', rowid, {
keys : true,
dataType : 'json',
url : '/api/v1/assetgrid/' + encodeURIComponent(rowid) + '/',
mtype : 'PATCH'
});
},
serializeRowData : function(data) {
return serializeAssetData(data);
},
ajaxRowOptions : {
contentType : "application/json"
},
width : 835,
shrinkToFit : false,
gridview : true,
height : "auto",
autoencode : true,
loadonce : true,
rowNum : 10,
rowList : [10, 20, 30],
pager : "#pager-account-assets",
viewrecords : true,
}).jqGrid("navGrid", "#pager-account-assets", {
search : false,
refresh : false
},
// edit options
{
closeAfterEdit : true,
mtype : "PUT",
serializeEditData : function(data) {
return serializeAssetData(data);
},
onclickSubmit : function(params, postdata) {
params.url = '/api/v1/assetgrid/' + encodeURIComponent(postdata[this.id + "_id"]) + '/';
},
ajaxEditOptions : {
contentType : "application/json",
dataType : "json"
},
afterSubmit : function(response, postdata) {
$('#jqgrid-account-assets').setGridParam({
datatype : 'json'
}).trigger('reloadGrid');
return [true, '', false];
},
beforeShowForm : function(form) {
centerDialog($("#editmodjqgrid-account-assets"));
}
},
// add options
{
closeAfterAdd : true,
mtype : "POST",
serializeEditData : function(data) {
return serializeAssetData(data);
},
onclickSubmit : function(params, postdata) {
params.url = '/api/v1/assetgrid/';
},
afterSubmit : function(response, postdata) {
$('#jqgrid-account-assets').setGridParam({
datatype : 'json'
}).trigger('reloadGrid');
return [true, ''];
},
ajaxEditOptions : {
contentType : "application/json",
dataType : "json"
},
beforeShowForm : function(form) {
centerDialog($("#editmodjqgrid-account-assets"));
}
},
// delete options
{
// Delete parameters
mtype : "DELETE",
serializeDelData : function() {
return "";
},
onclickSubmit : function(params, postdata) {
params.url = '/api/v1/assetgrid/' + encodeURIComponent(postdata) + '/';
},
beforeShowForm : function(form) {
centerDialog($("#delmodjqgrid-account-assets"));
},
afterSubmit : function(response, postdata) {
$('#jqgrid-account-assets').setGridParam({
datatype : 'json'
}).trigger('reloadGrid');
return [true, ''];
}
});
}
Upvotes: 0
Views: 889
Reputation: 327
I have been using tastypie in my django project. That works very smoothly, I didn't have such issue. To debug this first make sure where the problem is. Does the request reach server, does database query take too much time, does database connection break and like that to know whether database causing problem or your django code or tastypie or ajax calls.
Development server log, I suppose you know already. paste it's output here so that we can get more understanding.
To check mysql log : follow How to see log files in MySQL?
You are using browser to call these api then install django-debug-toolbar, it will fetch some info. try curl also instead of browser :
curl http://127.0.0.1:8000/api/v1/account/?user_id=1
Also see this. http://django-tastypie.readthedocs.org/en/latest/debugging.html
P.S: I can't comment as I have low reputation as of now.
Upvotes: 1