Env:
- nodejs 10.15.2, экспресс 4.16.4
- происходит в службе приложений Azure, а также в локальном тесте env
- с использованием "@azure/ storage-blob ":" ^ 10.3.0 "
Я создаю экспресс-приложение для загрузки / загрузки больших двоичных объектов в / из хранилища BLOB-объектов Azure.Все работает нормально: может загружать большие двоичные объекты, задавать метаданные, загружать большие двоичные объекты и т. Д. Но: когда прерыватели выходят на свое время ожидания, они вызывают исключение, которое завершает процесс узла.
Стек ошибок:
Fri Apr 19 2019 07:38:28 GMT+0000 (Greenwich Mean Time): Application has thrown an uncaught exception and is terminated:
Error: The request was aborted
at new RestError (D:\home\site\wwwroot\node_modules\@azure\ms-rest-js\dist\msRest.node.js:1397:28)
at a.<anonymous> (D:\home\site\wwwroot\node_modules\mql\node_modules\@azure\storage-blob\dist\index.js:1:11269)
at D:\home\site\wwwroot\node_modules\mql\node_modules\@azure\storage-blob\dist\index.js:1:1277
at Array.forEach (<anonymous>)
at a.abort (D:\home\site\wwwroot\node_modules\mql\node_modules\@azure\storage-blob\dist\index.js:1:1255)
at Timeout.<anonymous> (D:\home\site\wwwroot\node_modules\mql\node_modules\@azure\storage-blob\dist\index.js:1:519)
at ontimeout (timers.js:436:11)
at tryOnTimeout (timers.js:300:5)
at unrefdHandle (timers.js:520:7)
at Timer.processTimers (timers.js:222:12)
В моем локальном dev-env я поставил точку останова на необработанное исключение и обнаружил:
Событие наконец генерируется в event.js (emit)
Это вызвано RetriableReadableStream, (@ azure / blob-хранилище / dist / esm / lib / utils / RetriableReadableStream), см. «Aborter.addEventListener»:
function RetriableReadableStream(aborter, source, getter, offset, count, options) {
if (options === void 0) { options = {}; }
var _this = _super.call(this) || this;
_this.retries = 0;
_this.aborter = aborter;
_this.getter = getter;
_this.source = source;
_this.start = offset;
_this.offset = offset;
_this.end = offset + count - 1;
_this.maxRetryRequests =
options.maxRetryRequests && options.maxRetryRequests >= 0
? options.maxRetryRequests
: 0;
_this.progress = options.progress;
_this.options = options;
aborter.addEventListener("abort", function () {
_this.source.pause();
_this.emit("error", new RestError("The request was aborted", RestError.REQUEST_ABORTED_ERROR));
});
...
- Что в свою очередь вызвано прерыванием:
Aborter.prototype.abort = function () {
var _this = this;
if (this.aborted) {
return;
}
this.cancelTimer();
if (this.onabort) {
this.onabort.call(this);
}
this.abortEventListeners.forEach(function (listener) {
listener.call(_this);
});
this.children.forEach(function (child) { return child.cancelByParent(); });
this._aborted = true;
};
Мой прерыватель создан следующим образом:
createAborter(): Aborter {
let aborter = Aborter.timeout(5 * ONE_MINUTE);
aborter.onabort = () => {
console.warn(`AzureBlog.createAborter.onAbort: Request was aborted.`);
}
return aborter;
}
...и моя загрузка выглядит следующим образом:
async download(blobName: string): Promise<NodeJS.ReadableStream> {
const blockBlobURL = this.getBlockBlobUrl(blobName);
const downloadResponse = await blockBlobURL.download(this.createAborter(), 0);
if (!downloadResponse) {
throw new Error(`Download returned undefined.`);
}
if (!downloadResponse.readableStreamBody) {
throw new Error(`downloadResponse.readableStreamBody is undefined.`);
}
return downloadResponse.readableStreamBody;
}
... и я передаю его клиенту следующим образом:
self.expressApp.route('/download')
.get(jsonParser, async (req: Request, resp: Response) => {
handleDownload(req, resp);
}).post(jsonParser, async (req: Request, resp: Response) => {
handleDownload(req, resp);
});
...
let blobReadStream = await self.azureBlobStore.download(id);
blobReadStream.pipe(resp);
Как уже упоминалось, все работает до истечения времени ожидания.То, что я не получаю, это:
- Почему кто-то выбрасывает необработанную ошибку в базовую библиотеку, не позволяя потребителям lib ее перехватить?(Кстати, у меня была такая же проблема с лазурным узлом gremlin):
- Мой прерыватель onAbort () просто добавляет другого прослушивателя событий.Должен ли я удалить всех остальных слушателей, чтобы предотвратить эту ошибку?
- Почему вообще отключаются слушатели "abort"?Все запросы (загрузка, апстрим и т. Д.) Работают нормально в течение нескольких секунд.В примерах / документах ничего не говорится о ручном уничтожении / отключении прерывателя после успешного запроса.
Полагаю, я неправильно понял концепцию Абортера.Поэтому любая помощь очень ценится.
Большое спасибо!