最近AWSは、ラムダ関数用のnodejs8.10ランタイムの利用可能性を発表しました( Node.js 8.10ランタイムが利用可能 )。これはハッピーフローに最適であるように見えましたが、不幸なフローでいくつかの問題が発生しています。つまり、「UnhandledPromiseRejectionWarnings」が発生しています。
以下のコードを使用しています。その考えは、そのシナリオの不幸な流れをテストするために、存在しないオブジェクトへのキーを提供することです。私の目標は、エラーをログに記録してラムダから伝播させることです。ここでそれを処理する適切な方法がないためです(このラムダ関数内で新しいキーを取得する方法はありません)。また、呼び出し元でエラーを使用できるようにしたいと思います(たとえば、別のラムダ関数またはステップ関数)。
'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');
}
このラムダ関数を実行すると( SAM local を使用)、ラムダからエラーが返されますが、次の警告も表示されます。
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.
ラムダ関数からエラーを伝播しながらこれを処理する方法がわかりません(これは lambda function errors(node.js) に従って有効なシナリオになるはずです)。
以下のような(私にとって)同様のシナリオを実行しようとしましたが(エラーを特定して正確に理解するため)、どういうわけかここでは警告が表示されず、意図したとおりに機能しています(エラーはラムダから返されます)関数)。
'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;
}
ここで何が欠けているのですか、2つの例の動作が異なるのはなぜですか?ラムダ関数の外にエラーを伝播できるようにしながら、最初の例の警告を取り除くにはどうすればよいですか?任意の助けいただければ幸いです。
Promise/async関数内でスローまたはリジェクトし、それをキャッチで処理しない場合は常に、Nodeがその警告を返します。
AWSの example は、catchブロックでエラーをスローせず、それを返します。
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;
};
多数の非同期関数を持つ大規模なアプリケーションでは、単一の未処理のpromiseがノードプロセスを終了することは好ましくありません。これは、プロセスを終了するエラーをスローすることが望ましい動作である単純なLambda関数には適用されない場合があります。ただし、Nodeで警告したくない場合は、代わりにエラーを返します。
AWSが問題を修正したようです。 Node 8.10ランタイムを使用して次の関数でテストすると、未処理の拒否が表示されなくなります。
exports.handler = async (event) => {
throw new Error("broken")
};
実行が失敗したことをLambda関数に通知するコンテキストオブジェクトからfail
メソッドを使用して管理しました。
'use strict'
exports.handler = async function (event, context) {
try {
throw new Error('Something went wrong')
} catch (err) {
context.fail(err)
}
}