Node-redis: Повреждение данных на `get`

Созданный на 20 июл. 2016  ·  9Комментарии  ·  Источник: NodeRedis/node-redis

Обнаружено странное повреждение данных на get .

Пробовал с последними версиями redis: 3 и redis: 2 в docker + node версий 6.3.0 и 5.12.0.
Пытался разделить версию пакета redis пополам и обнаружил, что ошибка появилась в версии 2.6.0.

Тест на воспроизведение:

const assert = require('assert');

const redis = require('redis').createClient();

const data = JSON.stringify({
    "city_name": "Санкт-Петербург" // (russian language)
});
const key = 'somekey';

describe('redis', () => {

    before(done => redis.set(key, data, done));
    after(done  => redis.del(key, done));

    for (let i = 0; i < 10000; ++i) {
        it(`pass ${i}`, done => {
            redis.get(key, (err, results) => {
                assert(!err);
                assert.strictEqual(results, data);

                done();
            });
        })
    }

});

package.json:

{
  "devDependencies": {
    "mocha": "^2.5.3"
  },
  "dependencies": {
    "redis": "=2.6.0"
  }
}

Выход:

    ... (skipped)
    ✓ pass 1217
    ✓ pass 1218
    1) pass 1219
    2) "after all" hook

  1219 passing (4s)
  2 failing

  1) redis pass 1219:

      Uncaught AssertionError: '{"city_name":"��анкт-Петербург"}' === '{"city_name":"Санкт-Петербург"}'
      + expected - actual

      -{"city_name":"��анкт-Петербург"}
      +{"city_name":"Санкт-Петербург"}

Номер неудачного прохода является плавающим. Mocha работает с флагом -b для остановки при первом сбое, но если мы протестируем его без этого флага, он продолжит сбой после первого прерванного прохода:

    ... (skipped)
    ✓ pass 2477
    ✓ pass 2478
    1) pass 2479
    2) pass 2480
    3) pass 2481
    4) pass 2482
    5) pass 2483
    ... (all passes are failed until the end)

Первый сбой связан с повреждением данных, следующие сбои связаны с err в обратном вызове:

{ AbortError: Fatal error encountert. Command aborted. It might have been processed.
    at RedisClient.flush_and_error (/Users/silent/Projects/redis-test/node_modules/redis/index.js:350:23)
    at JavascriptRedisParser.Parser.returnFatalError (/Users/silent/Projects/redis-test/node_modules/redis/index.js:199:18)
    at handleError (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:172:10)
    at parseType (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:224:14)
    at JavascriptRedisParser.execute (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:404:20)
    at Socket.<anonymous> (/Users/silent/Projects/redis-test/node_modules/redis/index.js:267:27)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:177:18)
    at Socket.Readable.push (_stream_readable.js:135:10)
    at TCP.onread (net.js:542:20)
  code: 'NR_FATAL',
  command: 'GET',
  args: [ 'somekey' ],
  origin:
   ReplyError: Protocol error, got "c" as reply type byte. Please report this.
       at parseType (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:224:34)
       at JavascriptRedisParser.execute (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:404:20) } undefined

а иногда с этим:

     Uncaught RangeError: out of range index
      at RangeError (native)
      at concatBuffer (node_modules/redis-parser/lib/parser.js:357:13)
      at JavascriptRedisParser.execute (node_modules/redis-parser/lib/parser.js:389:21)
      at Socket.<anonymous> (node_modules/redis/index.js:267:27)
      at readableAddChunk (_stream_readable.js:177:18)
      at Socket.Readable.push (_stream_readable.js:135:10)
      at TCP.onread (net.js:542:20)

Не может воспроизводиться только с латинскими символами. Также не может воспроизводиться с помощью return_buffers: true .

Вот значение через redis-cli , может быть, это будет полезно:

127.0.0.1:6379> get somekey
"{\"city_name\":\"\xd0\xa1\xd0\xb0\xd0\xbd\xd0\xba\xd1\x82-\xd0\x9f\xd0\xb5\xd1\x82\xd0\xb5\xd1\x80\xd0\xb1\xd1\x83\xd1\x80\xd0\xb3\"}"
bug fixed / done

Все 9 Комментарий

Также воспроизводится с простой строкой Санкт-Петербург , без каких-либо JSON.{parse,stringify} .

127.0.0.1:6379> get somekey
"\xd0\xa1\xd0\xb0\xd0\xbd\xd0\xba\xd1\x82-\xd0\x9f\xd0\xb5\xd1\x82\xd0\xb5\xd1\x80\xd0\xb1\xd1\x83\xd1\x80\xd0\xb3"

@silentroach какую версию парсера вы сейчас используете? Я безуспешно пытался воспроизвести это.

парсер по умолчанию. вот архив для воспроизведения:

test.zip

npm i && npm t

моя текущая версия узла - 6.3.0, версия redis - 3.2.1 ( docker run redis ), os x

интересная вещь - сейчас все время запускаю тесты (пробовал примерно 50 раз), номер неудачной итерации всегда в этом наборе 2479, 6260, 7520

А без докера пробовали?

Хм, попробовал сейчас и тоже не могу воспроизвести :(
Но может воспроизводиться на производственном сервере Redis (с первой тестовой итерацией), которого нет в докере.

Постараюсь обнаружить отличия.

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

test.zip

(просто замените host на что-то отличное от вашего ip, чтобы работать через сеть)

не удалось с первой итерацией, в следующей вы можете найти ошибку out of range index .

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

теперь все в порядке, спасибо за быстрое исправление!

Спасибо за очень хороший отчет об ошибке! : +1:

Была ли эта страница полезной?
0 / 5 - 0 рейтинги