イタンジエンジニア、濱田です。
今回は、twilioを使っているサービスに障害が発生したときに、slackに通知したり、twilioにかかってきた電話を転送する仕組みを、aws lambda と aws api gatewayで実現する方法についてお話します。
背景
弊社では、twilioを使った自動応答サービスを展開しています。 このサービスに障害が発生したときに、次の3つを行う必要があります。 (この場合の障害は、サービスで起こったもので、twilio先生の障害ではありません。)
- そもそもの障害の検知
- twilioの050番号にかかってくる電話を、クライアントの03番号等に安全に転送してあげる
- 転送が行われたかの通知
1番目の検知は、様々な方法があるのでここでは割愛します。 2番、3番を実現するために、PRIMARY HANDLER FAILS を使う方法がありますよね。
かつては、サービスに障害が起きた時のために電話番号毎に作ったxmlファイルをs3に置き、そのurlを設定していました。 これでは、転送先の電話番号がクライアント毎に異なるため、大量のxmlの管理が発生してしまいます。 しかも、転送の通知をSMSに通知する設定をしており、社内の担当者が変わった時には、全てのファイルのSMSの送信先を変更するという作業が伴うものでした。
そこで、aws lambda と aws api gatewayを使って、
- twilioの転送結果をslackに通知して、エンジニアチーム全員で監視
- 障害発生時のアクションも、gateway側に設定して、一括管理
することにしました。
構成
今回の構成です。
ネットワーク設定等妥協して、lambdaと api gatewayが2セットあります。。。。
- PRIMARY HANDLER FAILS に 設定される api gateway の endpoint
- 上記のend pointから実行されるlambda1: slack通知と、転送先の電話番号のような情報を返す
- lambda1が叩く、転送先の電話番号のような情報を取得するための、api gate way の endpoint
- 転送先の電話番号のような情報を、RDSから取得して返すlambda2
実際のコード
lambdaの使い方、api gatewayの使い方、そして RDSから情報を取ってくる api gateway と lambdaの部分は省略します。
まずslack通知と、かかってきた電話の転送先を返すlambdaです。 今回はpythonです。
# -*- coding: utf-8 -*-
import urllib
import json
def lambda_handler(event, context):
slack_url = SLACK_URL
# アカウント情報取得は省略
## resultに入っている
# slackに通知する時の文言
text = """=======================================
なんかおかしいから、〇〇クライアントにかかってきた番号を転送したよ!
Phone_number: {0}
client_name: {1}""".format(event['param']['To'], result["client_name"])
params = {"text": text, "channel": "#channel", "username":"tenso-shitayo"}
f = urllib.urlopen(slack_url, json.dumps(params))
# ”とかで囲う必要があった
twilio_phone = '"' + result["phone_number"] + '"'
to_phone = '"' + result["transfer_phone"] + '"'
# ここで返した値を、gateway側で設定する。
return {'twilio_phone':twilio_phone, 'to_phone':to_phone}
まず統合リクエストの本文マッピングテンプレートを、application/jsonに変更し、下記コードにします。 ここで、paramsをlambdaにわたす際の整形を行います。
{
"param": {
#foreach( $key in $input.params().querystring.keySet() )
"$key": "$input.params().querystring.get($key)"#if( $foreach.hasNext ),#end
#end
}
}
次に統合レスポンスの、本文マッピングテンプレートをapplicaiton/xmlに変更し、下記コードにします。 ここで、twilioさんにやってもらいたいことを記述します。
今回は、転送と、転送先が全て通話中だった場合に、謝罪してもらっています。
#set($inputRoot = $input.path('$'))
<Response>
<Dial callerId=$inputRoot.twilio_phone >$inputRoot.to_phone</Dial>
<Say>"ただいまお電話が大変込み合っております。しばらくたってから、おかけ直し下さいませ。"</Say>
</Response>
最後に、メソッドレスポンスの、200のレスポンス文を、application/xml emptyモデルにしてデプロイ
後は、PRIMARY HANDLER FAILS に api gateway の endpointを設定しておけば、転送と、転送したことの通知をslackに通知してくれます。
まとめ
lambda と api gatewayを使えば、twilio の PRIMARY HANDLER FAILSの選択肢はどんどん増えて行く気がします。
後は、Serverless Framework等で管理できるといいのですが。。。。 それはこれからがんばります。