質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
AWS Lambda

AWS Lambdaは、クラウド上でアプリを実行できるコンピューティングサービス。サーバーのプロビジョニングや管理を要せず複数のイベントに対してコードを実行します。カスタムロジック用いた他AWSサービスの拡張やAWSの規模やパフォーマンスを用いたバックエンドサービスを作成できます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Q&A

1回答

2274閲覧

lambdaの非同期処理の実行結果を戻り値に返す方法を教えて下さい。

andre

総合スコア6

AWS Lambda

AWS Lambdaは、クラウド上でアプリを実行できるコンピューティングサービス。サーバーのプロビジョニングや管理を要せず複数のイベントに対してコードを実行します。カスタムロジック用いた他AWSサービスの拡張やAWSの規模やパフォーマンスを用いたバックエンドサービスを作成できます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

0グッド

0クリップ

投稿2018/07/30 18:25

前提・実現したいこと

AWSのlambdaからAWS MachineLearning(以下、ML)の実行結果を取得し、戻り値で返す処理を
実装しています。

発生している問題・エラーメッセージ

前提:
1.lambdaからMLを呼び出しコンソール上にMLの実行結果を確認することはできています。
2.MLの実行は非同期で行われます。MLの実行時のコールバック内で実行結果を戻り値で返すようにしました。

問題:コールバック内の戻り値をメイン処理であるexports.handlerの実行結果として受け取ることができません。

該当のソースコード(言語:Node.js 8.10)

ソースの処理順としては
lambdaのexports.handlerが実行される。

dispatchからPredictByMLが呼ばれる。

PredictByMLでmachinelearning.predictが実行される。
machinelearning.predictのコールバック内で実行結果をreturnする。

var AWS = require('aws-sdk'); var machinelearning = new AWS.MachineLearning(); var params_predict = { MLModelId: 'ml-JRpUTssnRek', /* required */ PredictEndpoint: 'https://realtime.machinelearning.us-east-1.amazonaws.com', /* required */ Record: { /* required */ 'age': '32.0', /* '<各種MLに渡すパラメータ>': ... */ } }; //----------------------------------------Helper Function End------------------- function predictCallbackHelper(err, data){ if (err) { console.log(err, err.stack); // an error occurred }else{ console.log(data); return { dialogAction: { type: 'Close', data, }, }; } } //----------------------------------------Helper Function End------------------- // Close dialog with the customer, reporting fulfillmentState of Failed or Fulfilled ("Thanks, your pizza will arrive in 20 minutes") function PredictByML(callback) { callback(machinelearning.predict(params_predict, predictCallbackHelper)); } function dispatch(intentRequest, callback) { console.log(`request received for userId=${intentRequest.userId}, intentName=${intentRequest.currentIntent.name}`); PredictByML(callback()); } exports.handler = (event, context, callback) => { // TODO implement try { dispatch(event, (response) => { callback(null, response); }); } catch (err) { callback(err); } };

ログ出力

Response: (質問時加筆:←この値をnullにならずにpredictCallbackHelperでreturnしている値を返したいのが解決したい課題です。)
null

Request ID:
"dbfcf5c9-9421-11e8-a1f7-6d136624d328"

Function Logs:
START RequestId: dbfcf5c9-9421-11e8-a1f7-6d136624d328 Version: $LATEST
2018-07-30T17:56:18.440Z dbfcf5c9-9421-11e8-a1f7-6d136624d328 request received for userId=user-1, intentName=OrderPizza
2018-07-30T17:56:19.301Z dbfcf5c9-9421-11e8-a1f7-6d136624d328 predict_result = init
2018-07-30T17:56:19.320Z dbfcf5c9-9421-11e8-a1f7-6d136624d328 { Prediction: (←質問時加筆:このJSON形式の情報がMLの実行結果です。これを戻り値として返したいです)
{ predictedLabel: 'admin.',
predictedScores:
{ 'admin.': 0.29799360036849976,
'blue-collar': 0.0013657491654157639,
entrepreneur: 0.03165128827095032,
housemaid: 0.04482463002204895,
management: 0.03435991331934929,
retired: 0.005821636412292719,
'self-employed': 0.05900626257061958,
services: 0.18993555009365082,
student: 0.0037378878332674503,
technician: 0.22878502309322357,
unemployed: 0.08908139914274216,
unknown: 0.01343707274645567 },
details: { Algorithm: 'SGD', PredictiveModelType: 'MULTICLASS' } } }
END RequestId: dbfcf5c9-9421-11e8-a1f7-6d136624d328
REPORT RequestId: dbfcf5c9-9421-11e8-a1f7-6d136624d328 Duration: 970.99 ms Billed Duration: 1000 ms Memory Size: 128 MB Max Memory Used: 31 MB

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

この値をnullにならずにpredictCallbackHelperでreturnしている値を返したいのが解決したい課題です。

無理です。
一度コールバック関数で非同期処理に入った時点でもう返ってくる手段がないのです。
所謂「コールバック地獄」という問題です。

Lambdaは長らくNode.jsのバージョンが6系と古かったのですが、
8系に上がったことでPromiseやasync / awaitが使えるようになっています。
なのでPromiseやasync / await等で勉強すればコールバック地獄への解決法になります。


…しかし、コードをざっと斜め読みしましたが、
根本のコールバックの使い方がかなり変ですね…
コールバック地獄や、Promise覚えろの前に、そりゃ動かんわと言ったところです。

一番致命的なのはここ。

JavaScript

1exports.handler = (event, context, callback) => { 2 // 非同期でtry-catchは無意味なので除去 3 dispatch(event, (response) => { 4 callback(null, response); 5 }); 6}; 7 8function dispatch(intentRequest, callback) { 9 console.log(`request received ...以下略`); 10 PredictByML(callback()); // <- なんでコールバック関数を引数無しで勝手に叩いてるの? responseがundefinedのまま全部の処理が終わっちゃうでしょ 11}

Node.jsは○○サーバにHTTPリクエストを飛ばしたり、ファイルを読み書きする処理は
非同期のやりたい事リストにとりあえず積み上げておく文化があります。
「イベントループ」あたりで調べれば情報が出てくると思いますが……

よって非同期の箇所をtry-catchで見張っても無駄で、
コールバック関数の第一引数をerr固定にして返す文化があります。
この思想を意識すると捗るんじゃないですかね?

投稿2018/07/31 01:58

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問