この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
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ハンズオンセミナー」を開催致します。導入を検討されておられる方は、是非、お申し込み下さい。
また音声を中心とした各種ソリューションの開発支援も行なっております。