webentwicklung-frage-antwort-db.com.de

Unbehandelte Versprechen auf AWS-Lambda mit async/await ablehnen

Kürzlich gab AWS die Verfügbarkeit der nodejs8.10-Laufzeitumgebung für ihre Lambda-Funktionen bekannt ( Node.js 8.10-Laufzeitumgebung ). Während dies für den glücklichen Fluss großartig schien, habe ich einige Probleme mit dem unglücklichen Fluss, d. H. Ich bekomme 'UnhandledPromiseRejectionWarnings'.

Ich verwende den folgenden Code. Die Idee ist, dass ich einen Schlüssel für ein nicht existierendes Objekt bereitstelle, um den unglücklichen Fluss für dieses Szenario zu testen. Mein Ziel ist es, dass der Fehler aus dem Lambda protokolliert und propagiert wird, da ich hier keinen vernünftigen Umgang damit habe (ich habe keine Möglichkeit, einen neuen Schlüssel innerhalb dieser Lambda-Funktion abzurufen). Ich möchte auch den Fehler im Aufrufer verwenden können (z. B. eine andere Lambda-Funktion oder Schrittfunktionen).

'use strict';

const AWS = require('aws-sdk');

exports.handler = async (event) => {
  let data;
  try {
    data = await getObject(event.key);
  } catch (err) {
    console.error('So this happened:', err);
    throw err;
  }

  return data;
}

const getObject = async (key) => {
  let params = {
    Bucket: process.env.BUCKET,
    Key: key
  };

  const s3 = new AWS.S3();

  let data;
  try {
    data = await s3.getObject(params).promise();
  } catch(err) {
    console.log('Error retrieving object');
    throw err;
  }

  console.log('Retrieved data');
  return data.Body.toString('utf8');
}

Wenn ich diese Lambda-Funktion (mit SAM local ) starte, bekomme ich den Fehler wie gewünscht aus dem Lambda, aber ich erhalte auch folgende Warnung (en):

2018-04-18T07:54:16.217Z    6ecc84eb-46f6-1b08-23fb-46de7c5ba6eb    (node:1) UnhandledPromiseRejectionWarning: NoSuchKey: The specified key does not exist.
    at Request.extractError (/var/task/node_modules/aws-sdk/lib/services/s3.js:577:35)
    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
    at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
    at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:683:14)
    at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:685:12)
    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
2018-04-18T07:54:16.218Z    6ecc84eb-46f6-1b08-23fb-46de7c5ba6eb    (node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
2018-04-18T07:54:16.218Z    6ecc84eb-46f6-1b08-23fb-46de7c5ba6eb    (node:1) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Ich bin mir nicht sicher, wie ich damit umgehen soll, während der Fehler immer noch aus der Lambda-Funktion heraus verbreitet wird (was nach Lambda-Funktionsfehlern ein gültiges Szenario sein sollte (node.js) ).

Ich habe auch versucht, ein ähnliches (für mich) Szenario auszuführen, wie das folgende (um den Fehler zu ermitteln und zu verstehen), aber irgendwie bekomme ich die Warnung nicht und es funktioniert wie beabsichtigt (der Fehler wird vom Lambda zurückgegeben Funktion).

'use strict';

const AWS = require('aws-sdk');

exports.handler = async (event) => {
  let data;
  try {
    data = await directBoom();
  } catch (err) {
    console.error('So this happened:', err);
    throw err;
  }

  return data;
}

const directBoom = async () => {
  let data;
  try {
    data = await Promise.reject(new Error('boom!')); 
  } catch(err) {
    throw err;
  }

  return data;
}

Was fehlt mir hier und warum verhalten sich die beiden Beispiele anders? Wie entferne ich die Warnung im ersten Beispiel, während ich den Fehler immer noch aus der Lambda-Funktion heraus verbreiten kann? Jede Hilfe wäre dankbar.

9
CodeVision

Jedes Mal, wenn Sie eine Versprechungs-/Asynchronfunktion ausführen oder ablehnen und nicht mit einem Haken behandeln, gibt Node diese Warnung zurück. 

Das example auf AWS wirft den Fehler nicht im catch-Block ab, sondern gibt ihn zurück: 

let AWS = require('aws-sdk');
let lambda = new AWS.Lambda();
let data;

exports.handler = async (event) => {
    try {
        data = await lambda.getAccountSettings().promise();
    }
    catch (err) {
        console.log(err);
        return err;
    }
    return data;
};

In einer großen Anwendung mit vielen asynchronen Funktionen wäre der Knotenprozess mit einem einzigen unbehandelten Versprechen, das beendet wird, fehlerhaft. Dies trifft möglicherweise nicht auf eine einfache Lambda-Funktion zu, bei der das Auslösen eines Fehlers, der den Prozess abbricht, das gewünschte Verhalten ist. Wenn Sie jedoch nicht möchten, dass Node Sie warnt, geben Sie stattdessen den Fehler zurück. 

5
Ryan Flaherty

Es scheint, dass AWS das Problem behoben hat. Beim Testen mit der folgenden Funktion unter Verwendung der Node 8.10-Laufzeit werden keine nicht behandelten Ablehnungen mehr angezeigt:

exports.handler = async (event) => { 
  throw new Error("broken")
};
1
Martin Donath

Dies ist mir mit der fail-Methode des Kontextobjekts gelungen, das die Lambda-Funktion darüber informiert, dass die Ausführung fehlgeschlagen ist.

'use strict'

exports.handler = async function (event, context) {
  try {
    throw new Error('Something went wrong')
  } catch (err) {
    context.fail(err)
  }
}
0
Kevin Rambaud