tarantool/node-tarantool-driver

Не всегда резолвится промис

monolithed opened this issue · 28 comments

При невыясненных обстоятельствах у меня бывают случаи когда промис не резолвится.

tarantool.insert(...)
    .then(result => { /* Не вызывается */  })
    .catch(error => { /* Не вызывается */  })

При этом, записи в базу добавляются.

Бегло нашел множество мест где как мне кажется такое возможно, например
Возможно из-за того, что условие в этом месте может не выполниться

PS: Кстати, почему бы не заменить vow на стандартные Promise, которые уже есть в ноде?

Понял, гляну.
PS: Перепишу.

Нету еще каких-то подробностей новых?

Повторяется стабильно.
У меня вызов операции insert завернут в десяток других промисов, но как они могут влиять на поведение не понимаю.

Весь код транслируется из ES6 через babel-node

// ... Куча промисов
// .. Тут стоит метка профайлера с логом
tarantool.insert(...)
    .then(result => { /* Не вызывается */  })
    .catch(error => { /* Не вызывается */  })
// .. Тут стоит метка профайлера  с логом 
// Данные в базу добавляются, 100%

Операцию insert выполняю в цикле из более чем 3000 итераций без каких-либо задержек (хотя я пробовал добавлять один элемент, колбек также не сработал).

Если вызвать insert отдельно от моего кода, то все работает.

Структура индексов такая:

return function (space)
    local name, city, host, rank, rate =
        1, 2, 3, 4, 5

    space:create_index('primary', {
        parts = {
            name, 'str',
            city, 'str'
        }
    })

    space:create_index('secondary', {
        type = 'tree',
        unique = false,
        parts = {
            host, 'str',
            rank, 'num',
            rate, 'num',
        }
    })
end

Пример массива данных:

[
    'google.com', 
    'Mountain View', 
    'google.com', 
    100, 
    2000, 
    [
          'YouTube',
          'Nest Labs',
          'FeedBurner', 
          'Songza'
    ],
    'Technologies'
]

@monolithed а что значит 3000 операций? Ты их паралельно записываешь через Promise.all или последовательно?
Понял ща проверю 10к записей подобных что будет.

Я получаю данные, затем в Promise.all мне приходит массив из 3000 элементов, затем в цикле я последовательно выполняю операцию вставки.
Все элементы попадают в базу, но зарезолвить их не получается (

Дебажить мне это дело очень проблематично, потому что код сперва транслируется препроцессором и брейкпоинты теряются.

@monolithed а эти данные совпадают для #11 ?

Данные те же, но там проблема пока ушла.

Вот часть кода, который отвечает за вставку данных:

/**
 * Устанавливает соединение с сервером приложения Tarantool
 *
 * @return {Promise}
 */
get connection () {
    return new Promise((resolve, reject) => {
        this.config.then(({ host, port, user, space_id }) => {
            let tarantool = new Tarantool({ host, port });

            // Прокидываем space_id в инстансе для комфортного доступа
            tarantool.space_id = space_id;

            tarantool.connect()
                .then(status => {
                    return tarantool.auth(user.name, user.password);
                })
                .then(status => {
                    resolve(tarantool);
                })
                .catch(error => {
                    reject('Failed to connect with Tarantool');
                })
            ;
        }, reject);
    });
}


/**
 * Записывает переданные данные в базу
 *
 * @param {Object} tarantool — Ссылка на открытое соединение
 * @param {Object} data — Данные фермы
 * @param {boolean} replace — Использовать операцию "replace"
 * @see normalize
 * @return {Promise}
 */
insert (tarantool, data, replace) {
    let tuple = this.normalize(data);

    return new Promise((resolve, reject) => {
        this.validate(tuple)
            .then(status => {
                let operation = replace ? 'replace' : 'insert';

                tarantool[operation](tarantool.space_id, tuple)
                    .then(resolve, error => {
                        Log.error('Insert operation error:',
                            error.message, '\n', tuple);

                        reject(error);
                    })
                ;
            })
            .catch(error => {
                Log.error('Validation error:',
                    error.message, '\n', tuple);

                reject(error);
            })
        ;
    });
}

@monolithed

[
    'google.com', 
    'Mountain View', 
    'google.com', 
    100, 
    2000, 
    [
          'YouTube',
          'Nest Labs',
          'FeedBurner', 
          'Songza'
    ],
    'Technologies'
]

вот конкретно этот кусок данных 10к раз вставленных отрабатывает но видимо там есть куски гораздо больше или как-то msgpack не справляется с дешифровкой или я где-то не правильно мержу куски данных или неправильно читаю их.

А сам по себе тарантул об ошибках не сообщает?

@monolithed хотя я не правильно сделал ща еще раз поправлю.
Вот когда поправил такая же байда. Это хорошо, теперь поисследую что там.
Хотя все равно не воспроизвелось просто оно 11 секунд у меня вставляется :( может и там у тебя где-то стоит таймаут?

А сам по себе тарантул об ошибках не сообщает?

Тарантул молчит.

msgpack не справляется с дешифровкой

Хм, а как это должно влиять на резолвинг промиса?

Вот когда поправил такая же байда. Это хорошо, теперь поисследую что там.

Это хорошая новость!

@monolithed так не воспроизвелось все таки. Просто у меня тупит машина, на ней еще всякое веселье крутится ._.
Если msgpack не справится то он не поймет к какому промису оно относится. Там оно по requestId расшифровывает ответ.

var dataSample = function(_, x){
                return [
    'google.com'+x,
    'Mountain View'+x,
    'google.com',
    100,
    2000,
    [
          'YouTube',
          'Nest Labs',
          'FeedBurner',
          'Songza'
    ],
    'Technologies'
];
            };
        var arr =[];
        for (var i=0; i<10000; i++)
            arr.push(dataSample(i, i));

Таким образом формирую данные для вставки.

Из-за того что msgpack синхронный?

@monolithed не из-за того что msgpack синхронный, а из-за того что данные какие-то не те вернулись. Ну или просто данные не правильно пришли, к примеру один пакет потерялся в процессе и все считай вся линия чтения в этом потоке нарушена.
Надо бы тоже покрыть этот сценарий какими-нибудь тестами, пока такого варианта не получал потому как в среде с плохой связью и потерянными пакетам не тестировал.

Я пробовал выводить данные, который приходят, они все стандартные, отличий вообще нет, разве что могут быть какие-то юникод-символы.

@monolithed а вот функция this.validate она всегда resolve/reject кидает?
Все данные что собираются сохраняются? Можешь провести какой-то анализ типа стадия сбора, а потом стадия сравнения того что собрано с тем что по итогу вставлено в базу.

Да, я же говорю, что в ее колбек я всегда попадаю:

/**
 * Валидация данных кортежа
 *
 * @param {Array}
 * @return {Promise}
 */
validate (data) {
    return new Promise((resolve, reject) => {
        try {
            let validate = jsen(this.schema);

            validate(data);

            if (validate.errors.length) {
                reject(validate.errors);
            }
            else {
                resolve(validate);
            }
        }
        catch (error) {
            reject(error.message);
        }
    })
}

@monolithed ща в мастер патч накатаю и попробуй с ним посмотреть что тебе в консоле выдастся. Ну или как время удобное будет. Где-то через полчаса залью его.

Слушай, похоже проблема действительно может быть в юникод-символах (тарантул их выводит как знаки вопроса в треугольнике), сейчас в базе таких нет и все промисы зарезолвились!

@monolithed ну давай ща проверю что там с unicode'ом. Просто русских символов хватит?

Эти символы приходят мне "извне", письмо парсится

@monolithed тогда скорее всего проблема в msgpack энкодинге/декодинге тогда лучше посмотреть просто обычный лог ошибок. Он куда-то должен был выкинуть ее по идеи, т.к. сам я ее не перехватываю. Сейчас накатаю чтобы оно в мастере пока писало куда-нибудь в диск ошибки эти кодирования декодирования.

Вот пример битой строки

��рилль

Но я это скопировал из базы, как-то же он туда попал

А вот сейчас даже этими символами все нормализовалось, уже раз 10 сделал экспорт и все Ок!

@monolithed я посмотрел вообщем-то в msgpack5 он String просто по сути как bytearray хранит, а читает его исключительно как utf-8 потом, так что желательно все привести к utf-8 перед тем как ложить в базу.

Хотя я чот сам туплю он по дефолту тоже пишет utf-8 для string, который write to buffer.

Кажется я нашел в чем проблема. Скоро все переделаю и будет новая версия с другими багами ._.