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
|
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.
|
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:
|
Manager:
|
||||||
|
|
||||||
* After executing the 'status' manager action, the "Status" manager events
|
* 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 */
|
/*! \brief queues.conf per-queue weight option */
|
||||||
static int use_weight = 0;
|
static int use_weight = 0;
|
||||||
|
|
||||||
|
/*! \brief queues.conf [general] option */
|
||||||
|
static int autofill_default = 0;
|
||||||
|
|
||||||
enum queue_result {
|
enum queue_result {
|
||||||
QUEUE_UNKNOWN = 0,
|
QUEUE_UNKNOWN = 0,
|
||||||
QUEUE_TIMEOUT = 1,
|
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->roundingseconds = 0; /* Default - don't announce seconds */
|
||||||
q->servicelevel = 0;
|
q->servicelevel = 0;
|
||||||
q->ringinuse = 1;
|
q->ringinuse = 1;
|
||||||
|
q->autofill = autofill_default;
|
||||||
q->moh[0] = '\0';
|
q->moh[0] = '\0';
|
||||||
q->announce[0] = '\0';
|
q->announce[0] = '\0';
|
||||||
q->context[0] = '\0';
|
q->context[0] = '\0';
|
||||||
@@ -1860,25 +1864,75 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||||||
}
|
}
|
||||||
|
|
||||||
return peer;
|
return peer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_our_turn(struct queue_ent *qe)
|
static int is_our_turn(struct queue_ent *qe)
|
||||||
{
|
{
|
||||||
struct queue_ent *ch;
|
struct queue_ent *ch;
|
||||||
|
struct member *cur;
|
||||||
|
int avl = 0;
|
||||||
|
int idx = 0;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
/* Atomically read the parent head -- does not need a lock */
|
if (!qe->parent->autofill) {
|
||||||
ch = qe->parent->head;
|
|
||||||
/* If we are now at the top of the head, break out */
|
/* Atomically read the parent head -- does not need a lock */
|
||||||
if ((ch == qe) || (qe->parent->autofill)) {
|
ch = qe->parent->head;
|
||||||
if (option_debug)
|
/* If we are now at the top of the head, break out */
|
||||||
ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
|
if ((ch == qe) || (qe->parent->autofill)) {
|
||||||
res = 1;
|
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 {
|
} 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)
|
if (option_debug)
|
||||||
ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
|
ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
|
||||||
res = 0;
|
|
||||||
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3302,6 +3356,9 @@ static void reload_queues(void)
|
|||||||
queue_persistent_members = 0;
|
queue_persistent_members = 0;
|
||||||
if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
|
if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
|
||||||
queue_persistent_members = ast_true(general_val);
|
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 */
|
} else { /* Define queue */
|
||||||
/* Look for an existing one */
|
/* Look for an existing one */
|
||||||
AST_LIST_TRAVERSE(&queues, q, list) {
|
AST_LIST_TRAVERSE(&queues, q, list) {
|
||||||
|
@@ -8,6 +8,25 @@
|
|||||||
; read into their recorded queues. Default is 'yes'.
|
; read into their recorded queues. Default is 'yes'.
|
||||||
;
|
;
|
||||||
persistentmembers = 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
|
; Note that a timeout to fail out of a queue may be passed as part of
|
||||||
; an application call from extensions.conf:
|
; an application call from extensions.conf:
|
||||||
@@ -73,11 +92,9 @@ persistentmembers = yes
|
|||||||
;wrapuptime=15
|
;wrapuptime=15
|
||||||
;
|
;
|
||||||
; Autofill will follow queue strategy but push multiple calls through
|
; Autofill will follow queue strategy but push multiple calls through
|
||||||
; at same time. WARNING: By setting this to yes, if you have a number
|
; at same time until there are no more waiting callers or no more
|
||||||
; of calls waiting in queue, and only a single member becoming available
|
; available members. The per-queue setting of autofill allows you
|
||||||
; at a time, it is more than likely NOT going to be the caller that's
|
; to override the default setting on an individual queue level.
|
||||||
; been waiting the longest that will get assigned to this newly available
|
|
||||||
; queue member.
|
|
||||||
;
|
;
|
||||||
;autofill=yes
|
;autofill=yes
|
||||||
;
|
;
|
||||||
|
Reference in New Issue
Block a user