diff --git a/UPGRADE.txt b/UPGRADE.txt index e6c52bff09e03e65c19152139cb8b3ca1c42868d..b6539d60e718a7c132b19e916f940efa1543cd55 100644 --- a/UPGRADE.txt +++ b/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 diff --git a/apps/app_queue.c b/apps/app_queue.c index 092aa709449315aa77211242a43cf8803f1933b6..5beb4b5fd8976b27b55986929c0a48a3c4878db3 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -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) { diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index ff00964e6ae12bdc9ccc80af28a217ded36d0c04..31aa2451458d21bb58efdef0444c5636b96e25d6 100644 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -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 ;