To start with, we’re going to create a simple ACD queue. It will accept callers and attempt to deliver them to a member of the queue.
In Asterisk, the term
member refers to a peer assigned to a queue that
can be dialed, such as SIP/0000FFFF0001
. An
agent technically refers to the Agent channel also
used for dialing endpoints. Unfortunately, the Agent channel is a
deprecated technology in Asterisk, as it is limited in flexibility and
can cause unexpected issues that can be hard to diagnose and resolve. We
will not be covering the use of chan_agent
, so be aware that we will generally
use the term member to refer to the telephone
device and agent to refer to the person who handles
the call. Since one isn’t generally effective without the other, either
term may refer to both.
We’ll create the queue(s) in the queues.conf
file, and manually add queue members to it through the
Asterisk console. In the section the section called “Queue Members”, we’ll
look into how to create a dialplan that allows us to dynamically add and
remove queue members (as well as pause and unpause them).
The first step is to create your queues.conf
file in the /etc/asterisk
configuration directory:
$
cd /etc/asterisk/
$
touch queues.conf
Populate it with the following configuration,
which will create two queues named [sales]
and [support]
. You can name them anything you want,
but we will be using these names later in the book, so if you use
different queue names from what we’ve recommended here, make note of your
choices for future reference:
[general] autofill=yes ; distribute all waiting callers to available members shared_lastcall=yes ; respect the wrapup time for members logged into more ; than one queue [StandardQueue](!) ; template to provide common features musicclass=default ; play [default] music strategy=rrmemory ; use the Round Robin Memory strategy joinempty=no ; do not join the queue when no members available leavewhenempty=yes ; leave the queue when no members available ringinuse=no ; don't ring members when already InUse (prevents ; multiple calls to an agent) [sales](StandardQueue) ; create the sales queue using the parameters in the ; StandardQueue template [support](StandardQueue) ; create the support queue using the parameters in the ; StandardQueue template
The [general]
section defines the default behavior and global options. We’ve only
specified two options in the [general]
section, since the built-in defaults are sufficient for our needs at this
point.
The first option is
autofill
, which tells the queue to distribute all waiting callers to
all available members immediately. Previous versions of Asterisk would
only distribute one caller at a time, which meant that while Asterisk was
signaling an agent, all other calls were held (even if other agents were
available) until the first caller in line had been connected to an agent
(which obviously led to bottlenecks in older versions of Asterisk where
large, busy queues were being used). Unless you have a particular need for
backward-compatibility, this option should always be set to
yes
.
The second option in the [general]
section of queues.conf
is
shared_lastcall
. When we enable shared_lastcall
, the last
call to an agent who is logged into multiple queues will be the call that
is counted for wrapup time[128] in order to avoid sending a call to an agent from another
queue during the wrap period. If this option is set to no
, the wrap timer will only apply to the queue
the last call came from, which means an agent who was wrapping up a call
from the support queue might still get a call from the sales queue. This
option should also always be set to yes
(the default).
The next section, [StandardQueue]
is the template we’ll apply to
our sales and support queues (we declared it a template by adding (!)
). We’ve defined the
musicclass
to be the default
music
on hold, as configured in the musiconhold.conf
file. The
strategy
we’ll employ is rrmemory
, which stands for Round-Robin with
Memory. The rrmemory
strategy works by
rotating through the agents in the queue in sequential order, keeping
track of which agent got the last call, and presenting the next call to
the next agent. When it gets to the last agent, it goes back to the top
(as agents log in, they are added to the end of the list). We’ve set
joinempty
to no
since it is
generally bad form to put callers into a queue where there are no agents
available to take their calls.
You could set this to yes
for ease of testing, but we would not
recommend putting it into production unless you are using the queue for
some function that is not about getting your callers to your agents.
Nobody wants to wait in a line that is not going anywhere.
The leavewhenempty
option is used to control whether callers should fall out
of the Queue()
application and continue
on in the dialplan if no members are available to take their calls. We’ve
set this to yes
because it makes no
sense to wait in a line that’s not going anywhere.
From a business perspective, you should be telling your agents to clear all calls out of the queue before logging off for the day. If you find that there are a lot of calls queued up at the end of the day, you might want to consider extending someone’s shift to deal with them. Otherwise, they’ll just add to your stress when they call back the next day, in a worse mood.
The alternative is to use GotoIfTime()
near the end of the day to
redirect callers to voicemail, or some other appropriate location in
your dialplan.
Finally, we’ve set
ringinuse
to no
, which tells
Asterisk not to ring members when their devices are already ringing. The
purpose of setting ringinuse
to no
is to avoid multiple calls to the same member
from one or more queues.
It should be mentioned that
joinempty
and leavewhenempty
are
looking for either no members logged into the queue, or all members
unavailable. Agents that are Ringing
or InUse
are not considered
unavailable, so will not block callers from joining the queue or cause
them to be kicked out when
and/or joinempty
=no
.leavewhenempty
=yes
Once you’ve finished configuring your queues.conf
file, you can save it and reload
the app_queue.so
module from your
Asterisk CLI:
$asterisk -r
*CLI>module reload app_queue.so
-- Reloading module 'app_queue.so' (True Call Queueing)
Then verify that your queues were loaded into memory:
localhost*CLI> queue show
support has 0 calls (max unlimited) in 'rrmemory' strategy
(0s holdtime, 0s talktime), W:0, C:0, A:0, SL:0.0% within 0s
No Members
No Callers
sales has 0 calls (max unlimited) in 'rrmemory' strategy
(0s holdtime, 0s talktime), W:0, C:0, A:0, SL:0.0% within 0s
No Members
No Callers
Now that you’ve created the queues, you need to configure your dialplan to allow calls to enter the queue.
Add the following dialplan logic to the extensions.conf
file:
[Queues] exten => 7001,1,Verbose(2,${CALLERID(all)} entering the support queue) same => n,Queue(support) same => n,Hangup() exten => 7002,1,Verbose(2,${CALLERID(all)} entering the sales queue) same => n,Queue(sales) same => n,Hangup() [LocalSets] include => Queues ; allow phones to call queues
We’ve included the Queues
context in the LocalSets
context so that our telephones can
call the queues we’ve set up. In Chapter 15, The Automated Attendant, we’ll
define menu items that go to these queues. Save the changes to your
extensidons.conf
file, and reload the
dialplan with the dialplan reload CLI
command.
If you dial extension 7001
or
7002
at this point, you will end up
with output like the following:
-- Executing [7001@LocalSets:1] Verbose("SIP/0000FFFF0003-00000001", "2,"Leif Madsen" <100> entering the support queue") in new stack == "Leif Madsen" <1--> entering the support queue -- Executing [7001@LocalSets:2] Queue("SIP/0000FFFF0003-00000001", "support") in new stack [2011-02-14 08:59:39] WARNING[13981]: app_queue.c:5738 queue_exec: Unable to join queue 'support' -- Executing [7001@LocalSets:3] Hangup("SIP/0000FFFF0003-00000001", "") in new stack == Spawn extension (LocalSets, 7001, 3) exited non-zero on 'SIP/0000FFFF0003-00000001'
You don’t join the queue at this point, as there are no agents in
the queue to answer calls. Because we have joinempty=no
and leavewhenempty=yes
configured in
queues.conf, callers will not be placed into the
queue. (This would be a good opportunity to experiment with the joinempty
and leavewhenempty
options in queues.conf
to better understand their impact
on queues.)
In the next section, we’ll demonstrate how to add members to your queue (as well as other member interactions with the queue, such as pause/unpause).
[128] Wrapup time is used for agents who may need to perform some sort of logging or other function once a call is done. It gives them a grace period of several seconds in order to perform this task before taking another call.