[Amazon Connect] GetCurrentMetricData でキューの状態をリアルタイムでブラウザに表示してみました
1 はじめに
AIソリューション部の平内(SIN)です。
Amazon Connect(以下、Connect)では、コンソールからリアルタイムでキューの状況を確認することが可能です。
今回は、このようなリアルタイムのキューの情報をブラウザで確認できるものを雑に作成してみました。
2 構成
構成は、以下の通りです。
- CloudWatch EventsでキックされたLambdaでConnectのAPIを叩き、取得したリアルタイムのデータをS3上に置きます。
- Connectの管理者は、CloudFront経由でS3上のファイル(index.html)を閲覧します。
- index.html内のJavaScriptは、更新されているリアルタイムのデータに基づいて表示します。
- データが更新されたことは、MQTTのpublishで伝達され、ブラウザ表示が更新されます。
- 表示する内容は、一般に公開するようなものではないので、WAFでIP制限しています。
3 GetCurrentMetricData
ConnectのAPIに用意されているGetCurrentMetricDataを使用するとリアルタイムなキューの状況を取得することができます。
https://docs.aws.amazon.com/connect/latest/APIReference/API_GetCurrentMetricData.html
(1) Request
リクエストのシンタックスは、次のとおりです。
POST /metrics/current/InstanceId HTTP/1.1 Content-type: application/json { "CurrentMetrics": [ { "Name": "string", "Unit": "string" } ], "Filters": { "Channels": [ "string" ], "Queues": [ "string" ] }, "Groupings": [ "string" ], "MaxResults": number, "NextToken": "string" }
- Filters(Required) 最大100個のキューID、又は、キューARNを指定する
- Groupings QUEUE | CHANNEL
- MaxResults 1ページあたりに返される結果の最大数を1〜100の範囲
- NextToken 次の結果セットを取得するためにトークン 期限は5分 後続のリクエストは、同じパラメータを使用する必要がある
- CurrentMetrics(Required) 取得するメトリックを名前と単位のセットで指定
メトリックス | 単位 |
---|---|
AGENTS_AVAILABLE(利用可能) | COUNT |
AGENTS_ONLINE(オンライン) | COUNT |
AGENTS_ON_CALL(通話中) | COUNT |
AGENTS_STAFFED | COUNT |
AGENTS_AFTER_CONTACT_WORK(ACW) | COUNT |
AGENTS_NON_PRODUCTIVE(使用不可) | COUNT |
AGENTS_ERROR(エラー) | COUNT |
CONTACTS_IN_QUEUE(キュー内の呼数) | COUNT |
OLDEST_CONTACT_AGE(最も長く待機している時間) | SECONDS |
CONTACTS_SCHEDULED(コールバックがスケジュールされている呼数) | COUNT |
(2) Rersponse
レスポンスのシンタックスは、次のとおりです。
HTTP/1.1 200 Content-type: application/json { "DataSnapshotTime": number, "MetricResults": [ { "Collections": [ { "Metric": { "Name": "string", "Unit": "string" }, "Value": number } ], "Dimensions": { "Channel": "string", "Queue": { "Arn": "string", "Id": "string" } } } ], "NextToken": "string" }
MetricResultsに、取得を希望したメトリックスが配列で返ります。
以下は、取得データの一例です。
{ "NextToken": null, "MetricResults": [ { "Collections": [ { "Metric": { "Name": "AGENTS_AVAILABLE", "Unit": "COUNT" }, "Value": 35 }, { "Metric": { "Name": "AGENTS_ONLINE", "Unit": "COUNT" }, "Value": 32 }, { "Metric": { "Name": "AGENTS_ON_CALL", "Unit": "COUNT" }, "Value": 15 }, { "Metric": { "Name": "AGENTS_STAFFED", "Unit": "COUNT" }, "Value": 45 }, { "Metric": { "Name": "AGENTS_AFTER_CONTACT_WORK", "Unit": "COUNT" }, "Value": 2 }, { "Metric": { "Name": "AGENTS_NON_PRODUCTIVE", "Unit": "COUNT" }, "Value": 0 }, { "Metric": { "Name": "AGENTS_ERROR", "Unit": "COUNT" }, "Value": 0 }, { "Metric": { "Name": "CONTACTS_IN_QUEUE", "Unit": "COUNT" }, "Value": 1 }, { "Metric": { "Name": "OLDEST_CONTACT_AGE", "Unit": "SECONDS" }, "Value": 1 }, { "Metric": { "Name": "CONTACTS_SCHEDULED", "Unit": "COUNT" }, "Value": 38 } ] } ], "DataSnapshotTime": "2019-03-03T00:33:02.663Z" }
(3) パーミッション
Lambdaに必要なパーミッションは、下記のみです。
connect:GetCurrentMetricData
(4) Lambdaの実装
今回実装したLambdaのコードは、以下のとおりです。
取得対象のキューは3つになっています。CurrentMetricsパラメータに、取得可能な全てのメトリックスを指定して、取得できたデータをそのままS3上にアップロードしています。
最後のAWSIotエンドポイントへのpublishは、ブラウザに更新を伝えています。
const aws = require('aws-sdk'); const connect = new aws.Connect({region:'ap-northeast-1'}); // ConnectのインスタンスID const instanceId ='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'; // 対象キューのID const queueId =['xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx']; const bucket = "bucketName"; const key = "CurrentMetricData.json"; exports.handler = async function (event) { // getCurrentMetricDataによるデータ取得 const params = { CurrentMetrics: [ { Name: 'AGENTS_AVAILABLE', Unit: 'COUNT' }, { Name: 'AGENTS_ONLINE', Unit: 'COUNT' }, { Name: 'AGENTS_ON_CALL', Unit: 'COUNT' }, { Name: 'AGENTS_STAFFED', Unit: 'COUNT' }, { Name: 'AGENTS_AFTER_CONTACT_WORK', Unit: 'COUNT' }, { Name: 'AGENTS_NON_PRODUCTIVE', Unit: 'COUNT' }, { Name: 'AGENTS_ERROR', Unit: 'COUNT' }, { Name: 'CONTACTS_IN_QUEUE', Unit: 'COUNT' }, { Name: 'OLDEST_CONTACT_AGE', Unit: 'SECONDS' }, { Name: 'CONTACTS_SCHEDULED', Unit: 'COUNT' } ], Filters: { Channels: ['VOICE'], Queues: queueId }, InstanceId: instanceId, }; const currentMetricData = await connect.getCurrentMetricData(params).promise(); // S3上のデータファイルの更新 const s3 = new aws.S3(); const params = { Bucket: bucket, Key: key, Body: JSON.stringify(currentMetricData), ContentType: "application/json", }; await s3.upload(params).promise(); // MQTTによるブラウザのリフレッシュ const endpoint = 'xxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com'; const region = 'ap-northeast-1'; const topic = "Refresh_Topic" const iotdata = new aws.IotData({ endpoint: endpoint, region: region }); const params = { topic: topic, payload: '{"action":"refresh"}', qos: 0 }; let result = await iotdata.publish(params).promise(); }
4 html(JavaScript)
こちらは、表示用のhtmlです。
設定ファイルconfig.jsonを読み込んで、その設定(表示対象項目、表示名及び、しきい値に応じた表示色)に基づいて、リアルタイムのデータを表示しています。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" type="text/css" href="style.css"> <script src="//code.jquery.com/jquery-1.12.4.min.js"></script> <script type="text/javascript" src="https://sdk.amazonaws.com/js/aws-sdk-2.355.0.min.js"></script> <script src="aws-iot-sdk-browser-bundle.js"></script> <script src="mqtt_refresh.js"></script> <title>Amazon Conect Realtime Report</title> </head> <body> <h1>Amazon Connect Realtime Report <div id="datetime"></div></h1> <div class="mainContainer"></div> </body> <script> const colors = {"default":"#aaaaaa", "green":"#05c46b", "yellow":"#ffd32a", "red":"#f53b57"}; let panels = []; let config; $.getJSON("config.json" , results => { config = results; // config.jsonから表示パネルを生成する let lineContainer; // 各列のコンテナ config.items.forEach( (item, i) => { if(i % config.colmax == 0) { // コンテナを追加して改行する lineContainer = $('<div class="lineContainer" />').appendTo('.mainContainer'); } const panel = $('<div class="panel" />') $('<div class="key" />').appendTo(panel); $('<div class="detail">' + item.key + '<br>( '+ item.detail +' )</div>').appendTo(panel); panel.appendTo(lineContainer); panels.push(panel); }); }); // ブラウザの更新 async function refresh() { // APIから取得したデータ const data = await getData(); for(var i=0;i<config.items.length; i++) { const key = config.items[i].key; const value = data[key]; const bgColor = getBgColor(key, value); panels[i].css('background-color', bgColor); panels[i].find('.key').text(value); } const now = new Date(); $('#datetime').html('['+ now.toLocaleTimeString() + ']'); } // リアルタイムのデータ(CurrentMetricData.json)の取得 async function getData() { return new Promise((resolve,reject)=>{ $.getJSON("CurrentMetricData.json" , results => { let data = {}; results.MetricResults[0].Collections.forEach( collection => { data[collection.Metric.Name] = collection.Value; }) console.log(JSON.stringify(data)) resolve(data); }); }) } // 値に応じたバックグラウンドカラーを取得する function getBgColor(key, value) { let bgColor = colors["default"]; config.items.forEach(item => { if(item.key == key) { // 該当キーを検索する Object.keys(colors).forEach( color => { if (item[color]) { // valueがどの色の範囲にあるかを検索する const start = Number(item[color].split('-')[0]); const end = Number(item[color].split('-')[1]); if (start <= value && value <= end) { bgColor = colors[color]; } } }); } }) return bgColor; } // MQTTリフレッシュのsubscribe mqtt_refresh(refresh); </script> </html>
5 設定ファイル
先のJavaScriptが読み込んでいる設定ファイルは、次のような形式になっています。
colmaxは、ラベル横に並べる数です。この数を超えると改行されます。 keyが表示対象のメトリックスで、red,yellow,greenで表示色を決定するためのしきい値を指定しています。これは、使用環境によって、その数値の意味するところが変わるため、それに対応できるようにしてみました。
{ "colmax":5, "items" : [ {"key": "AGENTS_AVAILABLE", "detail":"利用可能", "red":"0-1", "yellow":"2-3", "green":"4-999"}, {"key": "AGENTS_ONLINE", "detail":"オンライン", "red":"0-1", "yellow":"2-3", "green":"4-999"}, {"key": "AGENTS_ON_CALL", "detail":"通話中", "green":"0-20", "yellow":"21-30", "red":"31-999"}, {"key": "AGENTS_STAFFED", "detail":"スタッフ数", "red":"0-1", "yellow":"2-4", "green":"5-999"}, {"key": "AGENTS_AFTER_CONTACT_WORK", "detail":"通話後作業", "green":"0-1", "yellow":"2-3", "red":"4-999"}, {"key": "AGENTS_NON_PRODUCTIVE", "detail":"使用不可", "green":"0-1", "yellow":"2-3", "red":"4-999"}, {"key": "AGENTS_ERROR", "detail":"エラー", "green":"0-0", "yellow":"1-1", "red":"2-999"}, {"key": "CONTACTS_IN_QUEUE", "detail":"キュー内呼数", "green":"0-1", "yellow":"2-3", "red":"4-999"}, {"key": "CONTACTS_SCHEDULED", "detail":"コールバック待機数", "green":"0-1", "yellow":"2-3", "red":"4-999"} ] }
例えば、表示項目を絞って、設定ファイルを次のように編集すると、表示が変化します。
{ "colmax":5, "items" : [ {"key": "AGENTS_AVAILABLE", "detail":"利用可能", "red":"0-1", "yellow":"2-3", "green":"4-999"}, {"key": "AGENTS_ONLINE", "detail":"オンライン", "red":"0-1", "yellow":"2-3", "green":"4-999"}, {"key": "AGENTS_ON_CALL", "detail":"通話中", "green":"0-20", "yellow":"21-30", "red":"31-999"}, {"key": "AGENTS_AFTER_CONTACT_WORK", "detail":"通話後作業", "green":"0-1", "yellow":"2-3", "red":"4-999"}, {"key": "AGENTS_ERROR", "detail":"エラー", "green":"0-0", "yellow":"1-1", "red":"2-999"} ] }
6 その他
(1) CloudWatch Events
APIコールのためのLambdaの起動は、CloudWatch Eventsのスケージュールを使用しています。
一応、営業時間(09:00-18:00)の間だけ、5分おきに更新するという意味で、下記のように設定してみました。本当は、平日のみ(月〜金)としたかったのですが、UTCタイムゾーンからの変換が良くわからなくなって・・・ すいません、?にしちゃてます。
(2) S3 + Cloudfront + WAF
S3に配置されたオブジェクトは、以下のようになります。
こちらをCloudfront経由で、公開しています。
WAFでは、デフォルトで全てBlockとし、特定のIPだけAllowしています。
(3) MQTT
MQTT(AWSIot)経由で、ブラウザを更新している仕組みは、以下を利用しています。
参考:[AWS IoT] MQTTを使用して、Lambdaからブラウザを更新する方法〜aws-iot-device-sdk(aws-iot-sdk-browser-bundle.js)を使用する場合〜
7 最後に
今回は、ConnectのAPI(GetCurrentMetricData)を使用して、リアルタイムなメトリック表示を作ってみました。何も作らなくても、コンソールで確認することが可能ですが、「ちょっっと、ここを変えたい、アラームを出したい」みたいな要望を実現するとなると、こんな感じになって来るのかも知れません。
弊社ではAmazon Connectのキャンペーンを行なっております。
3月に「無料Amazon Connectハンズオンセミナー」を開催致します。導入を検討されておられる方は、是非、お申し込み下さい。
また音声を中心とした各種ソリューションの開発支援も行なっております。