1
1

More than 3 years have passed since last update.

Lambdaで値を返す方法まとめ

Last updated at Posted at 2021-09-01

結論

handlerをasyncにして普通にreturnで99.9%くらいOK

async + return

最も普通な方法です.

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};

async + returnでsetTimeoutする

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };

    setTimeout(() => {
        console.log("1000ms後");
    }, 1000);

    setTimeout(() => {
        console.log("2000ms後");
    }, 2000);

    return response;
};

のような場合, 1回目の実行でreturnするまでが1000ms未満の場合, console.logには出力されず, ウォームスタートした場合に次回以降出力されます.

1回目

START RequestId: 4978d8d6-0550-46d2-ad36-769858d22fa3 Version: $LATEST
END RequestId: 4978d8d6-0550-46d2-ad36-769858d22fa3
REPORT RequestId: 4978d8d6-0550-46d2-ad36-769858d22fa3  Duration: 2.50 ms   Billed Duration: 3 ms   Memory Size: 128 MB Max Memory Used: 85 MB  Init Duration: 391.34 ms

2回目 (2秒以上開ける)

START RequestId: e4dcdbb1-a150-43b4-9e80-c7a776837c16 Version: $LATEST
2021-09-01T03:17:49.058Z    4978d8d6-0550-46d2-ad36-769858d22fa3    INFO    1000ms後
2021-09-01T03:17:49.059Z    4978d8d6-0550-46d2-ad36-769858d22fa3    INFO    2000ms後
END RequestId: e4dcdbb1-a150-43b4-9e80-c7a776837c16
REPORT RequestId: e4dcdbb1-a150-43b4-9e80-c7a776837c16  Duration: 160.53 ms Billed Duration: 161 ms Memory Size: 128 MB Max Memory Used: 85 MB

console.logで出力される際についてくる実行IDが, 前回のものになっていることがわかります. このsetTimeout内のconsole.logは, Lambda実行後かつhandler実行前に実行されます.
(setTimeout(() => {console.log(new Date());}, 1000); してみましょう)

3回目実行直後に4回目

START RequestId: a87c55c4-73b6-402b-9b51-924d7ca7e178 Version: $LATEST
END RequestId: a87c55c4-73b6-402b-9b51-924d7ca7e178
REPORT RequestId: a87c55c4-73b6-402b-9b51-924d7ca7e178  Duration: 1.14 ms   Billed Duration: 2 ms   Memory Size: 128 MB Max Memory Used: 86 MB

ウォームスタートしていますが, 前回の実行のsetTimeoutが完了していないため, 何も出力されません.

5回目(2秒以上待機)

START RequestId: 20217709-e518-48fe-ad60-0fe1c7dd627e Version: $LATEST
2021-09-01T03:19:13.790Z    a87c55c4-73b6-402b-9b51-924d7ca7e178    INFO    1000ms後
2021-09-01T03:19:13.790Z    a87c55c4-73b6-402b-9b51-924d7ca7e178    INFO    1000ms後
2021-09-01T03:19:13.790Z    a87c55c4-73b6-402b-9b51-924d7ca7e178    INFO    2000ms後
2021-09-01T03:19:13.790Z    a87c55c4-73b6-402b-9b51-924d7ca7e178    INFO    2000ms後
END RequestId: 20217709-e518-48fe-ad60-0fe1c7dd627e
REPORT RequestId: 20217709-e518-48fe-ad60-0fe1c7dd627e  Duration: 1.47 ms   Billed Duration: 2 ms   Memory Size: 128 MB Max Memory Used: 86 MB

溜まっていたsetTimeoutが処理された後にLambdaを実行したため, 一気に表示されました.

詳しくはLambdaのライフサイクルで

非async + Promise

asyncで普通にreturnすれば値を返せるので, 当然Promiseを返すとうまくいきます.

exports.handler = (event) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return new Promise((resolve) => {
        resolve(response)
    });
};

非asyncな場合, 普通にreturnするだけだとnullになります.

callback

handlerの第3引数のcallbackで返す方法です. asyncかは問いません.

exports.handler = async (event, context, callback) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };

    callback(null, response);

    // callback後も実行される
    console.log("callback後");
    setTimeout(() => {
        response.statusCode = 400; // ここの実行後にcallbackに入れた値が返るため, 400が出力される
    }, 1000);
};

この場合, setTimeoutなどの非同期処理が全て終わってからcallbackに入れた値が返されます.

複数回callbackした場合

最も最初のcallbackのみ利用されます.

exports.handler = async (event, context, callback) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };

    setTimeout(() => {
        callback(null, response);
    }, 1000);
    callback(null, "hoge");
    callback(null, "fuga");
};
hoge

エラーの場合は第1引数

callback(new Error("era-"));

context

context.done, context.succeed, context.failが使えます.

exports.handler = async (event, context, callback) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };

    context.succeed(response);

    setTimeout(() => {
        console.log("fuga"); // この時点では実行されない (次回実行時にconsole.logされている)
    }, 1000);
    console.log("hogehoge"); // 実行される
};

つまり, 非同期は後回しになるものの, succeed以降も処理が続く, returnとcallbackの中間の性質を持っています. ぶっちゃけ使いません. async + returnでいいです.

callback, context, return全部並べてみる

普通に最初のものが処理されます.

exports.handler = async (event, context, callback) => {
    context.succeed("hoge");
    callback(null, "fuga");

    setTimeout(() => {
        console.log("a"); // 次回までお預け
    }, 1000);
    return "hige";
};
hoge
exports.handler = async (event, context, callback) => {
    callback(null, "fuga");
    context.succeed("hoge");

    setTimeout(() => {
        console.log("a"); // 実行される
    }, 1000);
    return "hige";
};
fuga

どのみちこんな書き方したらコードレビューで凄まじい数のchange requestがやってくるはずなので, 普通書かないです.

さいごに

他にも面白いのあったら教えてください🙏

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1