Задать вопрос
@mental_attack

Node.js+ajax+долгий sql-запрос. Почему данные не доходят до клиента?

Приложение - генератор отчетов, по данным, полученным из MS SQL SERVER.
На клиенте создается ajax запрос к серверу. Сервер запускает sql-запрос к скулю, получает данные, сериализует в json и отправляет клиенту. Клиент на основе данных ответа генерит таблицу и выводит на страницу.
Столкнулся с тем, что слишком долго выполняется sql-запрос (около 4х минут).
Eсли я захожу на сайт через nginx, то через 2 минуты после отправки ajax'а, получаю алерт "Ошибка error: Bad Gateway", а если захожу на сайт через localhost: port, т.е. минуя nginx, то получаю алерт "Ошибка error: error".
одновременно с этим в консоль выводится запись:
GET /result?IP=10.10.10.7&CODE=12&START=02.12.2013&END= 02.12.2014 200 120618ms
статус 200!!!
время выполнения хоть и указано 2 минуты +- пара секунд, но реально sql-запрос еще продолжает работать. Это становится ясно потому что еще через пару минут в туже консоль ниже выводятся записи
console.log("SerializeToJSON");
и
console.log("SendClient");
из соответствующих функций. Но к этому времени, возникает ощущение, что обратная связь с клиентом через объект res уже потеряна и в результате res.end(jsonData); уходит в никуда.
у кого есть какие мысли на этот счет? не знаю куда еще копнуть и что проверить?
Если уменьшить время время выполнения sql-запроса и соответственно объем полученных данных, путем подбора аргументов запроса, то все работает.
Для открытия коннекта и выполнения запроса использую модуль odbc
в документации ничего про таймауты на выполнения запроса не сказано.
Пробовал задать таймаут в строке коннекта вот так:
var Connect = "Driver={SQL Server};Server=" + ip + ";Database=MyDB;UID=sa;PWD=password;command timeout=600000;";
не помогло.
это код серверной части, обработчик ajax'а:
exports.result = function(req, res, curSessionId) {
    var params = new Params(
        req.param("IP"),
        req.param("CODE"),
        req.param("START"),
        req.param("END")
    );

 GetData(res, params, function(data) {
        SerializeToJSON(data, function(jsonData) {
            SendClient(res, jsonData);
        });
    });
}

 function GetData(res, params, callback) {
    var i = 0;
    var ip = params["p_IP"];
    var code = params["p_CODE"];
    var Start = params["p_START"];
    var End = params["p_END"];
    var tmpConnect = "Driver={SQL Server};Server=" + ip + ";Database=MyDB;UID=sa;PWD=password;command timeout=600000;";

    odbc.open(tmpConnect, function(err, tmpDB) {

        if (err) {
            return console.log("Error!\n" + err.message);
        }

        var SQL = "SELECT * FROM [dbo].[ufn_getJornalRealizNew]('" + Start + "', '" + End + "', '" + code + "')";

        tmpDB.query(SQL, function (err, rows, moreResultSets) {

            if (err) {
                return console.log("Error!\n" + err.message);
            }

            tmpDB.close();
            callback(rows);
        });
    });
 }

 function SerializeToJSON(data, callback) {
    var jsonData = JSON.stringify(data);
    console.log(SerializeToJSON);
    callback(jsonData);
 }

 function SendClient(res, jsonData) {
    console.log(SendClient);
    res.end(jsonData);
 }

 function Params(ip, code, Start, End) {
    this.p_IP = ip;
    this.p_CODE = code;
    this.p_START = Start;
    this.p_END = End;
 }

а вот код ajax ф-и на клиенте:
function QueryItem(ip, code, Start, End) {
        document.getElementById('btn').innerText = "Подождите...";
       //alert(ip + "@" + code + "@" + kad + "@" + Start + "@" + End);
        content = $.ajax({
            url: '/result',
            type: 'get',
            timeout: 600000,
            data: ({IP: ip, CODE: code, START: Start, END: End}),
            success: function(msg) {
                alert("Ответ от сервера получен!");
                SetTable(msg);
                document.getElementById('btn').innerText = "Сформировать"
            },
            error: onAjaxError
        }).responseText;
        return;
    }

var onAjaxError = function(xhr, status){
        //showLoading(false)
        var errinfo = { errcode: status };
        if (xhr.status != 200) {
            // может быть статус 200, а ошибка
            // из-за некорректного JSON
            errinfo.message = xhr.statusText;
        } else {
            errinfo.message = 'Некорректные данные с сервера';
        }
        onLoadError(errinfo);
}

var onLoadError = function(error) {
        var msg = "Ошибка "+error.errcode;
        if (error.message) msg = msg + ' :'+error.message;
        return alert(msg);
}

Сервер создан на основе модуля Express:
var express = require('express');
var app = express();

http.createServer(app).listen(config.get('port'), function(){
  console.log('Express server of the REPORTS project listening on port ' + config.get('port'));
});

Может это node (или кто-то другой) закрывает соединение с клиентом через 2 минуты? Может какие-то таймауты в ноде надо указать?
  • Вопрос задан
  • 3713 просмотров
Подписаться 2 Оценить Комментировать
Пригласить эксперта
Ответы на вопрос 2
ak-o
@ak-o
web-developer
Не очень разбираюсь в теме, но по аналогии с php могу сказать:
Если ожидание страницы больше таймаута в браузере, и браузер не получает никаких данных - соединение прерывается. На php решал вопрос выводом "пустоты" ( echo ''; ) и очисткой буфера. Браузер получал это "ничего" и ждал завершения работы. Может быть у вас похожая ситуация. Как поступить в случае с ajax\node.js к сожалению идей нет.
А еще подумал: может сериализация данных из mysql в сумме с запросом превышает таймаут.
Ответ написан
Комментировать
@mental_attack Автор вопроса
>может сериализация данных из mysql в сумме с запросом превышает таймаут.
только выполнение одного sql-запроса уже превышает видимо таймаут.
вопрос: таймаут чего превышается? как в chrome задать таймаут ожидания ответа сервера? да и возможно ли это вообще? в заголовках connection: keep-alive, если что...

UPD:
Что-то не могу ответить на коментарии, поэтому отредактирую здесь:
В ответ на коментарии ak-o:

ak-o: nginx используется только для проксирования. я может не совсем понятно написал... но sql-запрос не выполнился за 2 минуты. Вот как все происходит! Клиент послал ajax запрос web-серверу, web-сервер запустил sql-запрос к базе данных, который выполняется около 4 минут. По истечению 2 минут с момента отправки ajax-запроса от клиента web-серверу, я получаю ошибку, но на самом деле работа web-сервера все еще продолжается, sql-запрос продолжает выполняться и через какое-то время отрабатывает, возвращая набор данных из базы, после этого запускается сериализация этих данных и отправка сериализованных данных клиенту, но на самом деле данные уходят в никуда! Потому что похоже связь между web-сервером и браузером уже разорвана (ведь была же ошибка). Ошибку генерит обработчик error в ajax запросе. Вопрос почему и кто рвет соединение меня и беспокоит. )) Спасибо за советы, попробую. По-любму кто-то уже сталкивался с подобной проблемой, но вот нагуглить по её решению ничего не удалось. (

UPD2:
Попробовал и без sql-запроса. Поставил setTimeout на 3 минуты. Картина та же. Через 2 минуты ошибка, еще через минуту отправка ответа в никуда.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы