[AWS][Aurora]テーブルにレコードが挿入された際にLambdaを呼び出す方法


はじめに

"Aurora DBのテーブルにレコードが挿入されたらLambda関数を呼び出す"という方法に関して情報が少なかったため、備忘録として残しておきます。

参考

Amazon Aurora MySQL DB クラスターからの Lambda 関数の呼び出し
AuroraへのInsert TriggerでLambdaを呼びだしてServerlessで処理する
ストアドプロシージャの基本的ななにか

何がしたかったか

以下の処理を実現させるために、AuroraのInsert Triggerを利用してLambdaを呼び出す実装を行いました。

①DBのテーブルAにレコードが挿入されたら、そのレコードのidをAPIに渡す。
②レコードの内容を使ってAPIがある処理を行い、レスポンスを返す。
③レスポンスに含まれるデータをテーブルBに挿入する。

実装手順

DBエンジンにAuroraを使用したデータベースが構築されていることに加え、RDSとLambdaのIAM RoleおよびLambda関数が作成されていることを前提とします。作成手順が不明な方はこちらの記事を参照。

1.プロシージャを作成

プロシージャとはデータベース上で行う一連の処理(複数のSQL文)を関数として保存することで、それらの処理をいつでも呼び出せるようにしたものです。一般的な関数と違って戻り値はありませんが、引数を渡すことはできます。

ここでは「test_procedure」という名前のプロシージャを作成します。

DROP PROCEDURE IF EXISTS test_procedure;
DELIMITER ;;
CREATE PROCEDURE test_procedure (IN id INT) LANGUAGE SQL 
BEGIN
  CALL mysql.lambda_async('arn:aws:lambda:ap-northeast-1:9xxxxxxxxxx0:function:test_lambda_function',  
    CONCAT('{ "target_id" : "', id, '" }')
     );
END
;;
DELIMITER ;

以下、詳しく解説します。
まずは「test_procedure」という名前のプロシージャが既に存在しないかチェックし、存在する場合は削除します。

DROP PROCEDURE IF EXISTS test_procedure;

次にDELIMITER を使って, 区切り文字を一時的に変更します。なぜ変更するのかというとSQL文は通常はセミコロン(;)が処理の区切りとされますが、もし複数の処理を定義したい場合はこれでは都合が悪くなってしまいます。そのため、DELIMITER を使って区切り文字を一時的に変更し、後述するBEGINEND内に複数の処理を定義します。

DELIMITER ;;

これでセミコロン2つ;;が区切り文字として扱われます。

CREATE PROCEDUREでプロシージャを作成します。(IN id INT)は引数を意味します。ここではint型のidを引数にするという定義になります。もし引数が複数ある場合は(IN 〜, IN 〜)という形にします。

CREATE PROCEDURE test_procedure (IN id INT) LANGUAGE SQL 

BEGINEND内に行いたい処理(SQL文)を定義します。

BEGIN
  CALL mysql.lambda_async('arn:aws:lambda:ap-northeast-1:9xxxxxxxxxx0:function:test_lambda_function',  
    CONCAT('{ "target_id" : "', id, '" }')
     );
END
;;
DELIMITER ;

CALLによってプロシージャを呼び出します。ここで呼び出しているmysql.lambda_asyncはAurora上でデフォルトで定義されているプロシージャです。引数に指定のLambda関数のリソースネーム(ARN)を渡すことで、その関数を呼び出す処理を行ってくれます。また、CONCAT()で Lambda関数に渡すパラメータを指定(上記の場合は、挿入されたレコードのID)することができます。

このパラメータはLambda関数で呼び出す際は
lambda_handler(event, context)
eventに格納されているので event['target_id'] みたいな感じで呼び出します。

なお、ここでは1つのSQL文しか書いていませんが、;区切りで複数のSQL文を定義できます。

BEGIN
  SQL文1;
  SQL文2;
END

最後に先ほど定義した区切り文字;;を入れてプロシージャの定義を完了させ、DELIMITER ;で本来の区切り文字に戻します。

;;
DELIMITER ;

2.トリガーを設定

CREATE TRIGGERによって、テーブル(table_a)にレコードが挿入された際に上記で作成したプロシージャ(test_procedure)を呼び出す設定を行います。

DELIMITER ;;
CREATE TRIGGER trigger_test_procedure
  AFTER INSERT ON table_a
  FOR EACH ROW
BEGIN
  CALL test_procedure(NEW.id);
END
;;
DELIMITER ;

AFTER INSERT ON table_aでプロシージャの実行タイミングを定義しています。もしBEFORE INSERT ON table_aとした場合は、テーブルAにレコードが挿入される前にプロシージャが実行されます。

プロシージャの引数にあるNEWとは、挿入されたレコードを指します。つまり、NEW.idとは挿入されたレコードのidを意味します。

3.動作確認

あとはテーブルにレコードを挿入し、Lambdaの実行が確認できれば完了です。