Twilio Queue: Building a Call Queue Metrics Dashboard

September 07, 2012
Written by

Twilio Bug Logo

Whether you’re running a call center, just a small office, or have to deal with all of the incoming calls for an event one night, putting people on hold (aka call queuing) is important, but often a difficult technical process.

Twilio’s newest verb Queue simplifies this problem by providing a set of features that let you easily enqueue and dequeue callers, provide custom wait experiences and make it easy to get call queue metrics like the number of callers currently in a queue, and the average wait time of a queue.

In this post we’ll look specifically at how you can use the capabilities of Queue in a simple ASP.NET MVC application to build a simple dashboard that shows you metrics for a call queue.

If you want to skip ahead now, check out the live dashboard sample.

Placing Calls into a Queue

Before I can start to build a call queue dashboard, I first need to build a system that places callers into a call queue.  To do that I will create a new empty ASP.NET MVC project in Visual Studio and added a new controller class called CallController to which I’ll add a new action method named QueueCall.

public ActionResult QueueCall()
{
    var response = new TwilioResponse();

    response.Enqueue("Demo Queue", new {
        action= Url.Action("LeaveQueue"),       //url to call when the call is dequeued
        waitUrl = Url.Action("WaitInQueue")    //url to call while the call waits
    });

    return TwiML(response);
}

public ActionResult WaitInQueue(string CurrentQueueSize, string QueuePosition)
{
    var response = new TwilioResponse();

    response.Say(string.Format("You are number {0} in the queue.  Please hold.", QueuePosition));
    response.Play("http://demo.brooklynhacker.com/music/ramones.mp3");

    return TwiML(response);
}

public ActionResult LeaveQueue(string QueueSid)
{
    return new EmptyResult();
}

In the action method I can use use the TwilioResponse object, which is part of the Twilio TwiML helper library, to create a TwiML response that contains the Enqueue verb.  On the Enqueue verb I’ll set three attributes:

  • name – the name of the queue into which the caller will be placed
  • waitUrl – The URL used to provide TwiML to execute once the user is placed into the queue
  • action – The URL to request once the users leaves the queue.

Now I simply configure my Twilio phone number to request the QueueCall action method when a caller calls, and they will be placed into a queue.  Once in the queue, the caller will hear their position in the queue and then some awesome hold music.

When the caller leaves the queue by whatever action (being dequeued, hanging up, etc), Twilio will request the LeaveQueue action method.  I’ll use this later in the sample, but for now it simply returns an empty result.

First Metric: Current Queue Size

The first metric I want to show in my call queue dashboard is the number of callers currently waiting in the queue.  I want my dashboard to update automatically as users enter and leave the queue, so I’m going to use SignalR, Microsofts signaling framework to send queue size updates to asynchronously to my browser.

To get started I need to add SignalR to my MVC application, which I can do using the NuGet command line

Once SignalR is added to my project I need to create a Hub.  In SignalR, the Hub is what provides the persistent connection to each client.  To create a Hub, I’ll add a new class called QueueHub which will derive from the Hub base class, and then set the HubName attribute on the class:

HubName("queue")]
public class QueueHub : Hub
{
}

Next I need to update my View to include the SignalR Javascript and initialize the connection to the hub:

<script src="@Url.Content("~/Scripts/json2.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.signalR-0.5.3.min.js")" type="text/javascript"></script>
<script src="/signalr/hubs" type="text/javascript"></script>

<script type="text/javascript">
    $(function () {
        var conn = $.hubConnection(),
            queue = conn.createProxy("queue");

        conn.logging = true;
        conn.start();

        queue.on('reportQueueSize', function (currentSize) {
            $('#currentSize').text(currentSize);
        });
    });
</script>

Notice that when I initialize the connection, I’m also defining two client side methods that SignalR can call when the Hub needs to send a message to the client.

Finally, I need to update the action methods in the CallController to actually send the queue size messages to the client as callers enter and leave the queue.

public ActionResult WaitInQueue(string CurrentQueueSize, string QueuePosition)
{
	var context = GlobalHost.ConnectionManager.GetHubContext<Hubs.QueueHub>();
	context.Clients.reportQueueSize(CurrentQueueSize);

	var response = new TwilioResponse();
	response.Say(string.Format("You are number {0} in the queue.  Please hold.", QueuePosition));
	response.Play("http://demo.brooklynhacker.com/music/ramones.mp3");
	return TwiML(response);
}

As you can see, when Twilio requests the WaitInQueue action method it passes a parameter called CurrentQueueSize, so all I need to do when a user enters the Queue is send this to the client using SignalR.

When a user leaves the queue I have to do a bit more work.  Only the QueueSid is passed to the LeaveQueue action method, so there I have to look up the Queue using the Queue REST API to find out its current size.  To make this a bit easier I’m using the .NET helper library to get the Queue:

public ActionResult LeaveQueue(string QueueSid)
{
	var client = new TwilioRestClient(Queue_Demo.Settings.accountSid, Queue_Demo.Settings.authToken);
	var queue  = client.GetQueue(QueueSid);

	if (queue.RestException == null)
	{
	var context = GlobalHost.ConnectionManager.GetHubContext<Hubs.QueueHub>();
	context.Clients.reportQueueSize(queue.CurrentSize);
	}
	return new EmptyResult();
}

Now when I load the default View of my MVC application, if I call my Twilio number and enter the queue, I will see the call count automatically update to 1.

When I leave the queue, the call count should return to 0.

Second Metric: Average Wait Time

The second metric I want to include in my dashboard is the average wait time of callers in the queue.  This metric is different than the current queue size in that its constantly changing, even if the number of calls in the queue does not change.  The only time it stays constant is if there are no callers in the queue.

Because wait time is ever changing, instead of updating my dashboard only when callers arrive and leave the queue, I instead want to simply update the dashboard every ten seconds.  To do this I’m going to use an Azure Worker Role to poll the Twilio API, and then use SignalR to broadcast the wait time to my dashboard.  Using a worker roll is ideal in this instance because I want the polling to occur in the background on a regular interval.

To get started I first need to make sure I have the Windows Azure SDK installed and then add a new Windows Azure Worker Role to my existing Visual Studio solution:

When I add the Worker Roll a new class library is created for me that contains the worker roll stub code, including a Run method.  In the Run method, I can use the Twilio API to locate the specific queue I want to get the wait time for, and then start a loop which will poll Twilio every 10 seconds for that Queues wait time.

public override void Run()
{
    var client = new TwilioRestClient(Queue_Demo.Settings.accountSid, Queue_Demo.Settings.authToken);

    var queue = client.ListQueues().Queues.Where(q => q.FriendlyName == "Demo Queue").FirstOrDefault();

    if (queue!=null)
    {
        var queueSid = queue.Sid;

        var conn = new HubConnection(Queue_Demo.Settings.hubUrl);
        var hub = conn.CreateProxy("Queue");

        conn.Start();

        while (true)
        {
            Thread.Sleep(10000);

            var waitTime = client.GetQueue(queueSid).AverageWaitTime;

            Debug.WriteLine(waitTime);

            hub.Invoke("ReportAverageWait", new object[] { waitTime });
        }
    }
}

Each time the worker role gets the wait time, I can use the SignalR client API to send that value the Worker Role to the Hub and then in the Hub, broadcast that message out to my dashboard.

Dashboard Data Visualizations

Numbers are nice, but no dashboard is complete without some nice data visualizations, so as the last part of creating my call queue dashboard I used the HighCharts javascript chart widget to add charts showing the queue size and wait time values:

Because the charts are all client side, I’m using an array to store queue size and wait time values as they are sent via SignalR.  When a new value is added to an array I tell the appropriate HighChart to refresh itself to reflect the new value.

Summary

The new Call Queue features make it a breeze to create good experiences for both callers, and for managers managing call queue systems.  In this post we looked at how using TwiML and the Twilio API’s you can quickly create a simple dashboard to monitor your call queues.

To check out a live sample of the sample in thie post visit http://twilio-queue.azurewebsites.net.  You can also download all of the source code for this sample from GitHub. As always, I’d love to hear what you think of this post. If you have any questions or comments, you can tweet me at @devinrader, or shoot an email to devin@twilio.com.