Amazon AuroraからLambdaでTwilio！

当記事はアカウンティング・サース・ジャパン Advent Calendarの11日目です。

開発グループでマネージャーをしています。
普段コードはほとんど書いていないですが、AWS好きなのでAWSネタで行きます。

先日、Amazon Auroraのストアード・プロシージャーからLambda Functionの呼び出しができるようになったことが発表されました。
https://aws.amazon.com/jp/blogs/news/amazon-aurora-update-call-lambda-functions-from-stored-procedures-load-data-from-s3/

早速試してみましょう！

# 要件
1. 会員テーブルにデータが登録されたら、営業責任者にお褒めの電話
2. 会員テーブルからデータが削除されたら、営業責任者にお叱りの電話

# 構成概要
- Amazon AuroraにUsersテーブルを作成し、INSERTとDELETEのTriggerからストアード・プロシージャーをcallする
- ストアード・プロシージャーからLambdaをキック
- LamdaからTwilio APIをキック

# まずはLambdaの設定

「Create a Lambda Function」を押して、「Blank Function」選択
設定は、「VPC」のところは「No VPC」を選択
　※ VPCを選択すると、インターネットアクセスする為に一手間かかりますので、今回はこっち。
他の項目は適当に（「Lambda function code」は次項）。

# Lambda function code
```
exports.handler = function(event, context) {
  console.log(JSON.stringify(event, null, 2));

  var message = new Buffer(event.message, 'base64').toString()
  var queryString = require('querystring');
  twiml = {
    Twiml:  '<Response>\n' +
              '<Say voice="alice" language="ja-JP">' + message + '</Say>\n' +
            '</Response>'
  };
  url = "http://twimlets.com/echo?" + queryString.stringify(twiml);  

  var exec = require('child_process').exec;
  var cmd = 'curl -XPOST https://api.twilio.com/2010-04-01/Accounts/#####Twilio ACCOUNT SID#####/Calls ' + 
    '--data-urlencode "Url=' + url + '" ' +
    '--data-urlencode "To=+81xxxxxxxxxx" ' +
    '--data-urlencode "From=+81xxxxxxxxxx" ' + 
    '-u "#####Twilio ACCOUNT SID#####:#####Twilio AuthToken#####"';

  exec(cmd, function(error, stdout, stderr) {
    if (! error) {
        console.log('standard out: ' + stdout);
        console.log('standard error: ' + stderr);
        context.done();
    } else {
      console.log('error code: ' + error.code);
      console.log(error);
      context.fail();
    }
  });
};
```
以下の値をセットする。

| 設定項目     | 値 |
|:------------|:--|
| To          | かける相手（≒上司）の電話番号の、頭一桁を除いた番号を設定する  |
| From        | Twilioで取得した番号を設定  |
| ACCOUNT SID | TwilioのACCOUNT SID  |
| AUTH TOKEN  | TwilioのAUTH TOKEN  |

# Amazon Aurora用のRoleの作成

次にまずは、Auroraに設定するRoleを作成します。

1. 名前：forAuroraToLambda
2. アクセス許可タブのところで、「AWSLamdbaRole」をアタッチ
3. 信頼関係タブの編集のところで、"rds.amazonaws.com"をServiceの所に追加


# DBインスタンスの作成
| 設定項目 | 値 |
|:--------|:--------|
| エンジン  | Amazon Aurora（当然ｗ）  |
| パブリックアクセス可能  | はい  |
|Subnet| Publicで・・・|

後は適当に。

# クラスターにIAMロールを紐付け
1. クラスターの画面の上部にある「IAMロールの管理」をクリックする
2. そこで先程作成した「forAuroraToLambda」を選択し、完了


# DB Cluster Parameter Groupの作成
つぎに「DB Cluster Parameter Group」を作成します。

1. 新規で「DB Cluster Parameter Group」を「forLambda」で作成
2. パラメータの編集で、「aws_default_lambda_role」の値に、先程作成したRoleのARN（↓のようなやつ）を設定
   「arn:aws:iam::xxxxxxxxxx:role/forAuroraToLambda」
3. インスタンスの編集画面で、「DB クラスターのパラメータグループ」の値を、「forLambda」に変更
4. 再起動

# Database、Tableの作成

```
//Database
create database test;

//Table
create table users (id int auto_increment primary key, name char(100));
```

# ストアード・プロシージャーの作成

```
DROP PROCEDURE IF EXISTS lambda_test;
DELIMITER ;;
CREATE PROCEDURE lambda_test(IN message VARCHAR(255)) LANGUAGE SQL
BEGIN CALL mysql.lambda_async(
      // ↓ここに先程作成したLambdaのARNを設定する
      'arn:aws:lambda:ap-northeast-1:xxxxxxxxxx:function:helloTwilio',
               CONCAT('{"message":"',  to_base64(message),  '"}')

  );
END
;;
DELIMITER ;
```

# トリガーの作成

```
// Insert用
DROP TRIGGER IF EXISTS insert_trigger;
DELIMITER ;;
CREATE TRIGGER insert_trigger
  AFTER INSERT ON users
  FOR EACH ROW
BEGIN
  CALL lambda_test('いけてるやん');
END
;;
DELIMITER ;

// Delete用
DROP TRIGGER IF EXISTS delete_trigger;
DELIMITER ;;
CREATE TRIGGER delete_trigger
  AFTER DELETE ON users
  FOR EACH ROW
BEGIN
  CALL lambda_test('あかんがな');
END
;;
DELIMITER ;

```

# では、実際にやってみよう

直接UsersテーブルにレコードをInsertします。

```
// 会員追加
insert into users(name) values  ('hoge');
```

お褒めの電話がかかりましたか？

```
// 会員退会処理
delete from users where id = nnn;
```
   
お叱りの電話がかかりましたか？

# まとめ

Databaseのストアード・プロシージャーからLambdaを呼び出せることにより、様々な連携の実装コストが格段に下がるかもしれません。

ただ、2000年代前半のストアド地獄の二の舞いにならないよう、節度を持って使っていきましょう！


# 参考

http://dev.classmethod.jp/cloud/aws/invoke-lambda-from-aurora/
http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Aurora.Lambda.html
http://aws.typepad.com/aws_japan/2016/02/access-resources-in-a-vpc-from-your-lambda-functions.html