хранилище BLOB-объектов Azure nodejs v10 - приложение выдало необработанное исключение и завершено - PullRequest
0 голосов
/ 19 апреля 2019

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"?Все запросы (загрузка, апстрим и т. Д.) Работают нормально в течение нескольких секунд.В примерах / документах ничего не говорится о ручном уничтожении / отключении прерывателя после успешного запроса.

Полагаю, я неправильно понял концепцию Абортера.Поэтому любая помощь очень ценится.

Большое спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...