Lambdaから外部のサーバとHTTPによる通信を行ってみます。
とは言っても特別な制約はありませんので基本的に自由行うことができますが、実行時間によって課金される点に注意が必要です。相手方のサーバからレスポンスが中々返って来ないとその時間分だけ課金されます。またVPCの中にLambdaを置いて実行する場合はインターネットゲートウェイなどの設定が必要になります。
では行ってみましょう。
実際に試してみる
今回はNICTが公開しているAPIを利用し、日本標準時を取得するLambda関数を作成します。
準備
基本的な設定方法については過去記事を参照ください。 blog.katsubemakito.net
最初に「jst」という名前のプロジェクトを作成しました。
$ serverless Serverless: No project detected. Do you want to create a new one? Yes Serverless: What do you want to make? AWS Node.js Serverless: What do you want to call this project? jst
作成されたディレクトリに入ってnpm initしておきます。
$ cd jst
$ npm init
外部と通信を行うために「node-fetch」モジュールをインストールします。requestモジュールが非推奨になってしまったので今後は別の物を使った方が良さそうですね。
$ npm install node-fetch@2.x
※ node-fetchは3系からESmoduleに変更されました。これまで通りconst fetch = require('node-fetch')
とCommonJSを利用したい場合は2系を入れてください。
サンプルコード
serverless.yml
プロジェクトの設定を行います。URL/(stage)/jstをGETでリクエストすると、jst関数を実行します。
service: jst plugins: - serverless-offline provider: name: aws runtime: nodejs12.x environment: TZ: Asia/Tokyo functions: jst: handler: handler.jst events: - http: path: jst method: get
environmentはLambda実行時の環境変数を指定できる項目です。何となく分かったと思いますが、TZはTimeZoneの略称でここでは日本時間にするよう指定しています。この指定がないとUTCなどになってしまいますので時間を扱う場合はご注意を。
handler.js
実際のコードです。handler.jsの中に以下の関数をそのまま貼り付けます。
'use strict'; const fetch = require('node-fetch'); /** * GET /(stage)/jst */ module.exports.jst = async event => { const json = await getJST(); // 日本標準時を取得 return { statusCode: 200, body: JSON.stringify( { format: getFormatDate(json), raw: json, }, null, 2 ), }; }; /** * 日本標準時を取得する * * @return{object|undefined} */ async function getJST(){ const url = 'https://ntp-b1.nict.go.jp/cgi-bin/json'; const res = await fetch(url); if(res.ok){ return( res.json() ); } else{ return( undefined ); } } /** * YYYY-MM-DD hh:mm:ss形式で時刻を返却する * * @param {object} json * @return {string|boolean} */ function getFormatDate(json){ if( json === undefined ){ return(false); } const d = new Date(json.st * 1000); return( d.getFullYear() + "-" + ("00" + (d.getMonth() + 1)).slice(-2) + "-" + ("00" + d.getDate()).slice(-2) + " " + ("00" + d.getHours()).slice(-2) + ":" + ("00" + d.getMinutes()).slice(-2) + ":" + ("00" + d.getSeconds()).slice(-2) ); }
デプロイ
deployコマンドでAWSへ反映します。
$ serverless deploy
途中でURLが表示されるのでこれをメモします。
endpoints: GET - https://q88uum4ys8.execute-api.us-east-1.amazonaws.com/dev/jst
実行する
curlコマンドで挙動を確認します。日本時間が表示されたでしょうか?
$ curl 'https://q88uum4ys8.execute-api.us-east-1.amazonaws.com/dev/jst' { "format": "2020-05-18 15:12:19", "raw": { "id": "ntp-b1.nict.go.jp", "it": 0, "st": 1589782339.101, "leap": 36, "next": 1483228800, "step": 1 } }
料金の計算を行う
外部サーバとの通信を行う際に怖いのは実行時間が伸びて課金額が跳ね上がるのではないかという点ですね。
計算式
料金の計算は東京リージョンでは以下の通り。Lambdaを起動しっぱなしにしてくれるProvisioned Concurrencyは今回は置いておきます。
- 100万リクエストあたり 0.20USD
- メモリ1GB * 実行時間1秒あたり 0.0000125615USD
- 1ドル110円とすると0.001381765円
シミュレーション
仮に1分に1回リクエストされるとして、処理時間の違いにより月間でどの程度の開きが生まれるのか計算してみます。
- リクエスト数の課金は省いています
- Bの計算式は1分に1回実行されるとして 60回 * 24時間 * 30日 = 43,200
- 料金の計算式は『((A * B * C) / 1000) * 単価』となります。1000をかけているのはミリ秒で掛け算したのを秒に戻すためです。
実行時間が10倍になると単純に料金も10倍になりますねw Lambdaは安いとはいえ限界の15分(900秒)を1分毎に回し続けると5.5万円/月となるようですw
実際の実行時間を確認する
AWSマネジメントコンソールにログインし「API Gateway」から先ほど作成したプロジェクトへ移動します。リージョン毎に表示されますのでお目当ての物が無い場合は切り替えてください。ServerlessFrameworkのデフォルトはバージニア北部です。
以下の画面までたどり着いたらメソッド(GET)をクリック、一番右側の四角(lambda)をクリックします。
Lambda関数の編集画面に遷移するので「モニタリング」をクリック。
グラフ「Duration」に実行時間のグラフが表示されます。この中の「BilledDurationInMS」が課金対象の実行時間(ミリ秒)になります。
その下の方にある表で使用メモリなどさらに詳しい情報を確認できます。