【AWS Lambda使い方ガイド】Lambdaのハンドラーに課金対象外の内部タイマーをひっそりと仕込んでみる


2022/04/29

AWS Lambdaのハンドラ関数は受動的なイメージが持たれがちで、クライアント側から何かのリクエストをするまでは、アイドル状態のまま何も処理されずに待機したままだとと思われがちです。

実際には、
軽量なバックグラウンド処理であれば、自発的な内部処理として常時稼働状態を保つことが出来ます。

今回はあまり実用的な使い方ではないかも知れませんが、実験的な話としてAWS Lambdaに内部処理を行わせるためのハンドラの書き方を紹介します。

ちなみに今回の実行環境のターゲットは
node.jsですが、pythonのような他の言語でも考え方は同様に実装することができると思います。


AWS Lambdaへバックグラウンド処理を実装する

今回は再帰的なsetTimeout関数から定期的に実行されるタイマーをLambdaハンドラ内部に実装します。

以下がバックグラウンド処理を試す必要最低限のソースコードになります。

            
            "use strict";

//👇タイマーIDインスタンスをグローバルで保持
let timerId;

exports.handler = async (event, context) => {
    //👇最初のコール時にタイマー(10秒間隔)が処理を開始する
    if (timerId == null) {
        timerId = setTimeout(function tick() {
            console.log('HELLO, TIMER');
            timerId = setTimeout(tick, 10000);
        }, 10000);
    }

    const response = { statusCode: 200, body: '' };

    try {
        response.body = 'HELLO, CLIENT';
        return response;
    } catch (error) {;
        response.statusCode = 500;
        response.body = `ERROR: ${error}`;
        return response;
    }
}
        
この関数をLambdaにデプロイすると、内部処理有りのLambdaハンドラが完成です。

なお、初回に何かリクエストすることで初期化され、タイマーが開始されます。


Lambdaの内部処理時間はホントに課金対象時間外?

AWS Lambdaの内部処理時間が料金体系上、どのように扱われるのか少しだけ掘り下げて考えてみましょう。

AWS Lambdaの利用でCPU処理時間で課金される料金体系ですので、クラウドを使う身として気になるのは、今回のようなAWS Lambdaで
ハンドラー自身で閉じた内部処理をさせる場合に掛かった時間に課金されるのか否かです。

結論からいうと、
「Lambda内部で閉じた処理は課金時間対象外」な扱いになります。

参考|AWS Lambda 料金

公式のドキュメントの関連部分を抜粋すると、

            
            ...関数に対するリクエストの数とコードの実行時間に基づいて課金されます。

...呼び出しコールに応じて実行を開始するたびに、リクエストをカウントします。

実行時間は、コードの実行が開始された瞬間から、
その処理が返される、もしくは中止されるまでの時間で計算され、
値は 1 ミリ秒単位で切り上げられます。

料金は関数に割り当てたメモリ量により異なります。
AWS Lambda のリソースモデルでは、お客様が関数に必要なメモリ量を指定すると、
それに比例した CPU パワーとその他のリソースが割り当てられます。
メモリサイズが増えると、関数で利用可能な CPU にも同等の増加が発生します。
        

ということらしいので、クライアントからリクエストを受け、Lambdaからの処理結果を返すまでの時間に課金されることになります。

このため、クライアント側へレスポンスを返さないようなハンドラで閉じた内部処理には課金されることがないようです。

ただし、注意が必要なのは
Lambdaに割り当てるメモリとCPUリソース数の方で、設定の割にあまりに負荷の大きなバックグラウンド処理が常時走っている状況になってしまうと、そちらに処理時間を取られてしまいます。

結果、肝心のクライアントからのコールがリソース不足でコケてしまったり、課金される実行時間が無用に長くなってしまったりとするので、
潜在的に料金が割増になる可能性があります。

例えば今回の定期タイマーを内部処理に挟んだ際のLambdaの実行ログですが、

合同会社タコスキングダム|蛸壺の技術ブログ

見てのように、Lambdaで閉じたバックグラウンド処理は
Billed Duration(課金時間)の対象外に扱われています。

クライアントコールが開始されて、レスポンスが返し終わるまでの時間は全て課金されるようになっていることが分かります。


参考サイト

再帰的な(ネストされた) setTimeout | スケジューリング: setTimeout と setInterval

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。