booklista tech blog

booklista のエンジニアリングに関する情報を公開しています。

Amazon Connectを使った障害発生時の自動オンコール実現について

アイキャッチ

こんにちは。プロダクト開発部でクラウドインフラエンジニアとして業務を行っている高澤です。

インフラ構築以外の日常的な業務としては、以下のようなタスクを行っています。

  • 改善内容の発見・提案・実装
  • 異常の確認・対応
  • クラウドサービスが随時発表する機能の情報収集・検証

今回は、導入検討を行った Amazon Connect というサービスでの一斉架電方法についてお伝えします。

この記事で伝えたいこと

  • AWSが提供しているAmazon Connectサービスの概要
  • Amazon Connectを利用し、自動で一斉架電をする方法、コードについて

架電の自動化に至る背景

なんらかの障害が発生した場合、担当者に障害の発生を知らせ、対応の開始を促すことになります。

業務中であればメール・SMS・Slackなどで気づく確率が高いですが、 業務時間外や取り込み中には1回携帯電話が鳴ったり、振動したくらいでは気づかないこともあります。 電話をかけることにより、通知よりも長時間の呼び出しができるため有効な手段となります。

また、電話を架けて障害の発生を気づかせる場合にも、 1人だけがその電話で対応を開始しても対応できる内容に限界があるので、 「自動で」「一斉に電話をかけ」「障害に気づかせたい」という要望が生まれました。

ポイントをまとめると以下となります。

  • 障害が発生した場合に、電話で障害の発生を通知し対応を促したい
  • 複数人に一斉架電をしたい

Amazon Connectの技術紹介

AWSにて提供されているサービスのうち、電話を架ける、ということが可能なサービスであるAmazon Connectについて軽く紹介をします。

Amazon Connectの利用用途として主に想定されているのは、コンタクトセンターとして電話を受けたり、電話をかけたりすることによりお客様対応を効率的に実現することです。 Amazon Connectを使うことでウェブブラウザー上で電話を受けたり、別の人に電話を転送したり、など様々なことができます。 音声、SMS、メールなどを通してお客様とのコミュニケーションを取ることができるサービスです。

このAmazon Connectで、今回は電話を架ける、という機能を主に使っていきます。

作成した環境の紹介

構成図

使用する要素は以下の4つです。

  1. Datadog(Monitorを使用)
  2. AWS SNS
  3. AWS Lambda
  4. Amazon Connect

要素は以下のような流れで連携します。

Datadogから一斉架電までの流れ

初期設定について

Amazon Connectの導入・初期設定については、 以下の記事を参考とさせていただき、構築しました。

参考URL: DatadogとAmazon Connectを用いた電話通知実施してみた【監視】

現在は追加で以下の2点の申請が必要でした。

  1. 電話番号を取得するために申請が必要1

  2. 携帯電話に架電したい場合は、電話番号を取得後に別途緩和申請が必要

一斉架電の実現について

ここから、複数人に同時に架電をする+容易に架電対象とするかどうかの設定変更を可能にしていきます。

同時に架けられる数の調査

一斉に電話を架ける場合、同時に何人にかけられるのかを確認してみます。

参考URL: Amazon Connect サービスクォータ

この中の、「インスタンスあたりのアクティブな同時呼び出しの数」が「同時に何人にかけられるのか」に該当します。

デフォルトは10ですので、10人に同時に架けられるようです。

こちらは気になったので AWS Support Centerにて問い合わせをし、確認が取れています。

発信と着信の両方を合算した数 であり、インスタンス内の電話番号すべての音声通話数 とのことです。

今回は発信しかしませんので、同時であれば10人までの一斉架電が可能です。

10人以上に同時架電したい場合は、緩和申請にて依頼してみることになると思われます。

一斉架電の実現パターンについて

一斉架電の実現パターンとしては、有効な選択肢として以下の2つが考えられました。

  • パターン1

    • 1つのSNSから1つのLambdaを呼び、その中で複数人に架電
      • メリット:SNSを1つ指定するだけでグループに架電可能
      • デメリット:変更があった場合にグループ情報の編集が必要
  • パターン2

    • 複数のSNSから複数のLambdaを呼び、1つのLambdaでは1人に架電
      • メリット:変更があった場合にトリガからSNSを外すだけでOK
      • デメリット:トリガに複数のSNSの設定が必要

架電の対象とする人数がそこまで多くならないのではないか、という見込み、および 対象者のつけ外しのしやすさを選択し、今回はパターン2を選択しました。 この場合、1つのSNS=1人への架電、となります。 人数がとても多い場合はパターン1のほうが良いと思われます。

架電用のAmazon Connectの問い合わせフロー(SNS, Datadog設定, Lambda)について

Amazon Connectの問い合わせフロー

参考とさせていただいた記事と同じです。

こちらは1回作れば変更はない想定のため、コードではなく手動で作成しました。

SNSについて

コードで管理したい、人数分作らなければならない、ということもあり、 AWS CDKにてSNS,Lambda部分を作成しました。 SNSとLambdaが一対一となるように作成します。

SNS-Phone-Call-for-A → Lambda-for-A
SNS-Phone-Call-for-B → Lambda-for-B

といった形で作っています。

以下、Amazon Connect設定用Stackと、interface,settingの該当部分のコード例です。

/* eslint-disable no-new */
import { Duration, Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as sns from "aws-cdk-lib/aws-sns";
import * as subs from "aws-cdk-lib/aws-sns-subscriptions";
import * as environment from "../environment"; //設定用に作成しているファイルです

/**
 * Amazon Connect設定用Stack
 */
export class AmazonConnectSettingStack extends Stack {
  constructor(
    scope: Construct,
    id: string,
    target: string, // dev,staging,prod,などのデプロイターゲットのstringです
    setting: environment.EnvironmentSetting, // 設定です
    props?: StackProps
  ) {
    super(scope, id, props);

    /**
     * Amazon Connect呼び出し用のLambdaの作成
     */
    // Lambda関数に付与するIAMロール
    const connectRole = new iam.Role(
      this,
      `${target}-amazon-connect-lambda-role`,
      {
        assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
        path: "/service-role/",
        inlinePolicies: {
          ConnectPolicy: new iam.PolicyDocument({
            statements: [
              new iam.PolicyStatement({
                actions: [
                  "logs:CreateLogGroup",
                  "logs:CreateLogStream",
                  "logs:PutLogEvents",
                ],
                resources: ["*"],
              }),
              // Amazon Connectの権限
              new iam.PolicyStatement({
                actions: [
                  "connect:Start*",
                  "connect:Describe*",
                  "connect:List*",
                ],
                resources: ["*"],
              }),
            ],
          }),
        },
      }
    );

    // ユーザーごとに回してLambda関数を作成
    setting.AMAZON_CONNECT_DEFINITION!.ConnectUserLists.forEach(
      (ConnectUserList) => {
        // Lambda関数を作成
        const callFunction = new lambda.Function(
          this,
          `${ConnectUserList.UserName}-call`,
          {
            runtime: lambda.Runtime.PYTHON_3_9,
            handler: "lambda_function.lambda_handler",
            architecture: lambda.Architecture.ARM_64,
            code: lambda.Code.fromAsset("lib/resources/lambda/connect-call/"),// Lambdaのファイルを置いている場所を指定します
            timeout: Duration.seconds(10),
            role: connectRole,
            environment: {
              DESTINATION_NAME: ConnectUserList.UserName,
              DESTINATION_PHONE_NUMBER: ConnectUserList.PhoneNumber,
              CONTACT_FLOW_ID: setting.AMAZON_CONNECT_DEFINITION!.ContactFlowId,
              INSTANCE_ID: setting.AMAZON_CONNECT_DEFINITION!.InstanceId,
              SOURCE_PHONE_NUMBER:
                setting.AMAZON_CONNECT_DEFINITION!.SourcePhoneNumber,
            },
          }
        );

        // SNS,サブスクリプション作成
        const snsTopic = new sns.Topic(
          this,
          `${ConnectUserList.UserName}-call-sns`,
          {
            displayName: `Phone-Call-for-${ConnectUserList.UserName}`,
            topicName: `Phone-Call-for-${ConnectUserList.UserName}`,
          }
        );
        snsTopic.addSubscription(new subs.LambdaSubscription(callFunction));
      }
    );
  }
}


//Amazon CONNECT 該当interfaceの抜粋
//(略)

/**
 * Amazon CONNECT用の宛先名・電話番号
 */
export interface ConnectUserList {
  UserName: string; // 受話する人の名前(主に識別のため)なるべく英数字
  PhoneNumber: string; // 電話番号 (日本の 080-xxxx-yyyyの場合は +8180xxxxyyyy 形式)
}

/**
 * Amazon Connectの定義
 */
export interface AmazonConnectDefinition {
  InstanceId: string; // AmazonConnectのインスタンスID
  ContactFlowId: string; // AmazonConnectのコンタクトフローID
  SourcePhoneNumber: string; // 発信元電話番号
  ConnectUserLists: ConnectUserList[]; // 受話するユーザーリスト
}

//(略)


//setting の該当設定例の抜粋
//(略)

  AMAZON_CONNECT_DEFINITION: {
    InstanceId: "ABCDE",
    ContactFlowId: "ABCDE",
    SourcePhoneNumber: "+8100000000", //発信元電話番号
    // ConnectUserListsはAmazon Connectの同時発信制限により、10までとしてください(緩和可能)
    ConnectUserLists: [
      { UserName: "A-user", PhoneNumber: "+818000000000" },
      { UserName: "B-user", PhoneNumber: "+818000000000" },
    ],
  },

//(略)

上記のようにCDKで作らない場合も、SNSとLambdaを作成していけばOKです。

Lambda functionについて

こちらも参考とさせていただいた記事とほぼ同じです。

違いは、1つのLambdaにて1人に電話を掛けるようにしているため、電話番号の取得場所を直接環境変数から取っていることです。

冗長とはなりますが、CDKで管理されているため、あまり気にする必要はなくなります。

# -*- coding: utf-8 -*-
# Amazon Connectを利用し、電話をかける
# Datadogでの指定を細かく可能とするため、1ユーザーごととする
import logging
import os
import boto3

logger = logging.getLogger()
logger.setLevel(logging.INFO)


def lambda_handler(event, context):
    logger.info("Event: " + str(event))

    # Datadogからのイベントからアラート名を取得し、読み上げに使う
    datadogSubject = event["Records"][0]["Sns"]["Subject"]
    message = datadogSubject + "が発生しました。確認・対応をしてください。"

    # ログ用
    logger.info("DESTINATION_NAME: " + os.environ["DESTINATION_NAME"])  # 電話宛先名
    logger.info("Message: " + str(message))

    # Amazon Connectで架電
    connect = boto3.client("connect")
    response = connect.start_outbound_voice_contact(
        DestinationPhoneNumber=os.environ["DESTINATION_PHONE_NUMBER"],
        ContactFlowId=os.environ["CONTACT_FLOW_ID"],
        InstanceId=os.environ["INSTANCE_ID"],
        SourcePhoneNumber=os.environ["SOURCE_PHONE_NUMBER"],
        Attributes={"alarm": message * 2},  # 2回メッセージを繰り返した文言を読み上げる
    )
    logger.info(str(response))

Datadog設定について

Datadogのモニタが変化した場合、電話をしたい場合は、DatadogのモニタのNotify your teamにて、 以下の例のように設定をします。 一人ずつ別れているため、ここでつけ外しが容易です。

Datadogモニタ設定

テスト

Datadogでテストを行います。 複数のSNSをつけてテストし、ほぼ同時に複数の電話に着信があれば完成です。

では、楽しいAmazon Connect架電ライフをお送りください。


  1. AWS Support Center にて、Amazon Connectで使用する電話番号を取得したい旨を伝えると、必要な書類や手続きについて回答が貰えます。内容は変更になる可能性がありますので、詳細はAWS Support Center にてお問い合わせください。