mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 20:20:07 +00:00
Fix autofill behavior in app_queue and document it's functionality in queues.conf.sample and UPGRADE.txt
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@24543 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
20
UPGRADE.txt
20
UPGRADE.txt
@@ -73,6 +73,26 @@ Applications:
|
||||
queue member channel that is taking the call. This is useful when trying
|
||||
to link recording filenames back to a particular call from the queue.
|
||||
|
||||
* The old/current behavior of app_queue has a serial type behavior
|
||||
in that the queue will make all waiting callers wait in the queue
|
||||
even if there is more than one available member ready to take
|
||||
calls until the head caller is connected with the member they
|
||||
were trying to get to. The next waiting caller in line then
|
||||
becomes the head caller, and they are then connected with the
|
||||
next available member and all available members and waiting callers
|
||||
waits while this happens. This cycle continues until there are
|
||||
no more available members or waiting callers, whichever comes first.
|
||||
The new behavior, enabled by setting autofill=yes in queues.conf
|
||||
either at the [general] level to default for all queues or
|
||||
to set on a per-queue level, makes sure that when the waiting
|
||||
callers are connecting with available members in a parallel fashion
|
||||
until there are no more available members or no more waiting callers,
|
||||
whichever comes first. This is probably more along the lines of how
|
||||
one would expect a queue should work and in most cases, you will want
|
||||
to enable this new behavior. If you do not specify or comment out this
|
||||
option, it will default to "no" to keep backward compatability with the old
|
||||
behavior.
|
||||
|
||||
Manager:
|
||||
|
||||
* After executing the 'status' manager action, the "Status" manager events
|
||||
|
@@ -234,6 +234,9 @@ static int queue_persistent_members = 0;
|
||||
/*! \brief queues.conf per-queue weight option */
|
||||
static int use_weight = 0;
|
||||
|
||||
/*! \brief queues.conf [general] option */
|
||||
static int autofill_default = 0;
|
||||
|
||||
enum queue_result {
|
||||
QUEUE_UNKNOWN = 0,
|
||||
QUEUE_TIMEOUT = 1,
|
||||
@@ -575,6 +578,7 @@ static void init_queue(struct ast_call_queue *q)
|
||||
q->roundingseconds = 0; /* Default - don't announce seconds */
|
||||
q->servicelevel = 0;
|
||||
q->ringinuse = 1;
|
||||
q->autofill = autofill_default;
|
||||
q->moh[0] = '\0';
|
||||
q->announce[0] = '\0';
|
||||
q->context[0] = '\0';
|
||||
@@ -1860,25 +1864,75 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
||||
}
|
||||
|
||||
return peer;
|
||||
|
||||
}
|
||||
|
||||
static int is_our_turn(struct queue_ent *qe)
|
||||
{
|
||||
struct queue_ent *ch;
|
||||
struct member *cur;
|
||||
int avl = 0;
|
||||
int idx = 0;
|
||||
int res;
|
||||
|
||||
/* Atomically read the parent head -- does not need a lock */
|
||||
ch = qe->parent->head;
|
||||
/* If we are now at the top of the head, break out */
|
||||
if ((ch == qe) || (qe->parent->autofill)) {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
|
||||
res = 1;
|
||||
if (!qe->parent->autofill) {
|
||||
|
||||
/* Atomically read the parent head -- does not need a lock */
|
||||
ch = qe->parent->head;
|
||||
/* If we are now at the top of the head, break out */
|
||||
if ((ch == qe) || (qe->parent->autofill)) {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
|
||||
res = 1;
|
||||
} else {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
|
||||
res = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* This needs a lock. How many members are available to be served? */
|
||||
|
||||
ast_mutex_lock(&qe->parent->lock);
|
||||
|
||||
ch = qe->parent->head;
|
||||
cur = qe->parent->members;
|
||||
|
||||
while (cur) {
|
||||
if (cur->status == 1)
|
||||
avl++;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
|
||||
res = 0;
|
||||
ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
|
||||
|
||||
if (qe->parent->strategy == 1) {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in!\n", avl);
|
||||
avl = 1;
|
||||
}
|
||||
|
||||
while ((idx < avl) && (ch) && (ch != qe)) {
|
||||
idx++;
|
||||
ch = ch->next;
|
||||
}
|
||||
|
||||
/* If the queue entry is within avl [the number of available members] calls from the top ... */
|
||||
if (ch && idx < avl) {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
|
||||
res = 1;
|
||||
} else {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
|
||||
res = 0;
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&qe->parent->lock);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -3302,6 +3356,9 @@ static void reload_queues(void)
|
||||
queue_persistent_members = 0;
|
||||
if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
|
||||
queue_persistent_members = ast_true(general_val);
|
||||
autofill_default = 0;
|
||||
if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
|
||||
autofill_default = ast_true(general_val);
|
||||
} else { /* Define queue */
|
||||
/* Look for an existing one */
|
||||
AST_LIST_TRAVERSE(&queues, q, list) {
|
||||
|
@@ -8,6 +8,25 @@
|
||||
; read into their recorded queues. Default is 'yes'.
|
||||
;
|
||||
persistentmembers = yes
|
||||
;
|
||||
; AutoFill Behavior
|
||||
; The old/current behavior of the queue has a serial type behavior
|
||||
; in that the queue will make all waiting callers wait in the queue
|
||||
; even if there is more than one available member ready to take
|
||||
; calls until the head caller is connected with the member they
|
||||
; were trying to get to. The next waiting caller in line then
|
||||
; becomes the head caller, and they are then connected with the
|
||||
; next available member and all available members and waiting callers
|
||||
; waits while this happens. The new behavior, enabled by setting
|
||||
; autofill=yes makes sure that when the waiting callers are connecting
|
||||
; with available members in a parallel fashion until there are
|
||||
; no more available members or no more waiting callers. This is
|
||||
; probably more along the lines of how a queue should work and
|
||||
; in most cases, you will want to enable this behavior. If you
|
||||
; do not specify or comment out this option, it will default to no
|
||||
; to keep backward compatability with the old behavior.
|
||||
;
|
||||
autofill = yes
|
||||
;
|
||||
; Note that a timeout to fail out of a queue may be passed as part of
|
||||
; an application call from extensions.conf:
|
||||
@@ -73,11 +92,9 @@ persistentmembers = yes
|
||||
;wrapuptime=15
|
||||
;
|
||||
; Autofill will follow queue strategy but push multiple calls through
|
||||
; at same time. WARNING: By setting this to yes, if you have a number
|
||||
; of calls waiting in queue, and only a single member becoming available
|
||||
; at a time, it is more than likely NOT going to be the caller that's
|
||||
; been waiting the longest that will get assigned to this newly available
|
||||
; queue member.
|
||||
; at same time until there are no more waiting callers or no more
|
||||
; available members. The per-queue setting of autofill allows you
|
||||
; to override the default setting on an individual queue level.
|
||||
;
|
||||
;autofill=yes
|
||||
;
|
||||
|
Reference in New Issue
Block a user