Обнаружено странное повреждение данных на 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\"}"
Также воспроизводится с простой строкой Санкт-Петербург
, без каких-либо 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 какую версию парсера вы сейчас используете? Я безуспешно пытался воспроизвести это.
парсер по умолчанию. вот архив для воспроизведения:
npm i && npm t
моя текущая версия узла - 6.3.0, версия redis - 3.2.1 ( docker run redis
), os x
интересная вещь - сейчас все время запускаю тесты (пробовал примерно 50 раз), номер неудачной итерации всегда в этом наборе 2479, 6260, 7520
А без докера пробовали?
Хм, попробовал сейчас и тоже не могу воспроизвести :(
Но может воспроизводиться на производственном сервере Redis (с первой тестовой итерацией), которого нет в докере.
Постараюсь обнаружить отличия.
Невозможно воспроизвести на локальном Redis, но может воспроизводиться при подключении к другому компьютеру в сети с изменением строки данных для более сложного примера.
(просто замените host на что-то отличное от вашего ip, чтобы работать через сеть)
не удалось с первой итерацией, в следующей вы можете найти ошибку out of range index
.
Я только что выпустил новую версию парсера, в которой проблема устранена. Прошу прощения за то, что забыл многобайтовые символы.
теперь все в порядке, спасибо за быстрое исправление!
Спасибо за очень хороший отчет об ошибке! : +1: