2016-07-07 14 views
2

私はサーバレスフレームワークの初心者です。 Serverlessのベストプラクティスを学習するとき。 hereサーバレスフレームワークのベストプラクティス

「ラムダコードの外部で外部サービスを初期化する」に関する質問があります。 これを実装する方法は?たとえば :コードの下handler.js

const getOneUser = (event, callback) => { 
    let response = null; 
    // validate parameters 
    if (event.accountid && process.env.SERVERLESS_SURVEYTABLE) { 
    let docClient = new aws.DynamoDB.DocumentClient(); 
    let params = { 
     TableName: process.env.SERVERLESS_USERTABLE, 
     Key: { 
     accountid: event.accountid, 
     } 
    }; 
    docClient.get(params, function(err, data) { 
     if (err) { 
     // console.error("Unable to get an item with the request: ", JSON.stringify(params), " along with error: ", JSON.stringify(err)); 
     return callback(getDynamoDBError(err), null); 
     } else { 
     if (data.Item) { // got response 
      // compose response 
      response = { 
      accountid: data.Item.accountid, 
      username: data.Item.username, 
      email: data.Item.email, 
      role: data.Item.role, 
      }; 
      return callback(null, response); 
     } else { 
      // console.error("Unable to get an item with the request: ", JSON.stringify(params)); 
      return callback(new Error("404 Not Found: Unable to get an item with the request: " + JSON.stringify(params)), null); 
     } 
     } 
    }); 
    } 
    // incomplete parameters 
    else { 
    return callback(new Error("400 Bad Request: Missing parameters: " + JSON.stringify(event)), null); 
    } 
}; 

問題のは、どのように私のラムダコードの外DynamoDBの初期していることです。

アップデート2:

はコードの下に最適化されていますか?

Handler.js

let survey = require('./survey'); 
module.exports.handler = (event, context, callback) => { 
    return survey.getOneSurvey({ 
     accountid: event.accountid, 
     surveyid: event.surveyid 
    }, callback); 
}; 

survey.js

let docClient = new aws.DynamoDB.DocumentClient(); 
module.exports = (() => { 
    const getOneSurvey = (event, callback) {.... 
     docClient.get(params, function(err, data)... 
     .... 
    }; 

    return{ 
    getOneSurvey : getOneSurvey, 
    } 
})(); 
+0

* "コードは最適化されていますか?" *このルールではなく、いいえと言います。 'handler'が呼び出されるたびに' survey。getOneSurvey() 'が呼び出され、そのたびに新しい' aws.DynamoDB.DocumentClient'が作成されます。これは、ハンドラが呼び出されるたびにではなく、コードが最初にロードされたときに、適切なスコープの変数に1回だけ割り当てられます。 –

+0

OK!私はdocClientをmodule.exportsの外に置きました。最初に読み込まれ、1つのdocClientしか作成されません。私の考えは正しい? – Jim

答えて

6

ここで問題になっている引用です:

は、あなたのラムダコード

の外の外部サービスを初期化します

サービス(DynamoDBなど)を使用する場合は、ラムダコードの外部で初期化を行ってください。 Ex:モジュールの初期化子(Nodeの場合)、または静的コンストラクタ(Javaの場合)。ラムダ関数内のDDBへの接続を開始すると、そのコードはすべての呼び出しで実行されます。

つまり、同じファイル内ですが、実際のハンドラコードの前にはありません。

let docClient = new aws.DynamoDB... 
... 
const getOneUser = (event, callback) => { 
.... 
    docClient.get(params, ... 

コンテナが開始されると、ハンドラの外側のコードが実行されます。後続の関数呼び出しで同じコンテナを再利用すると、外部サービスを再度インスタンス化しないことでリソースと時間を節約できます。コンテナはしばしば再利用されますが、各コンテナは一度に1つの同時リクエストのみを処理し、再利用される頻度とコントロールの範囲内で処理されます。関数を更新しない限り、既存のコンテナは彼らは機能の古いバージョンを持っていたので、再利用されます。

あなたのコードは書かれたとおりに動作しますが、最適化されていません。

現世代のNode.js Lambda関数(ノード4.x/6.x)で発生するこのアプローチの警告は、一部のオブジェクト、特に外部サービスへのリテラル永続接続を作成するオブジェクトが、イベントループが空にならないようにします(一般的な例は、サーバーとのライブTCP接続を保持するmysqlデータベース接続ですが、これとは対照的に、トランスポートプロトコルはHTTPSなので、実際にはコネクションレスです)。この場合は、context.callbackWaitsForEmptyEventLoopfalseに設定してコールバックを呼び出す前に、コンテナをフリーズする前に別の方法またはallow lambda to not wait for an empty event loopを実行する必要があります。ただし、必要な場合のみ、その意味を十分に理解している必要があります。インターネット上の何人かの人がそれが良いアイデアだと言っているので、デフォルトで設定すると、その後、不思議なバグを潜在的にもたらすでしょう。

+0

完璧な答えをありがとう!私は私の質問を更新しました! – Jim

+0

テストと嘲笑はどうですか? 'aws-sdk-mock'を使用しています。そこには次のものがあります。_ SDKのメソッドを疑似化するために、AWSサービスをテスト中の関数内で初期化する必要があります。したがって、これを動作させるためには、 'exports.handler = function(event、context){' [例2を参照](https:// www)内で 'var dynamoDb = AWS.DynamoDB();' .npmjs.com/package/aws-sdk-mock) – iaforek

+0

@iaforek * prima facie *、それは実際に問題のように思える。なぜなら、コードがそのように書かれていれば最適なデザインにならないからだ。明らかに(!?)ハンドラ関数を実行するたびにオブジェクトを初期化するオーバーヘッドは、各コンテナに対して1回だけ行うよりも効率が悪いです。 –

関連する問題