Fix autofill behavior in app_queue and document it's functionality in queues.conf...
authorBJ Weschke <bweschke@btwtech.com>
Wed, 3 May 2006 20:01:30 +0000 (20:01 +0000)
committerBJ Weschke <bweschke@btwtech.com>
Wed, 3 May 2006 20:01:30 +0000 (20:01 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@24543 65c4cc65-6c06-0410-ace0-fbb531ad65f3

UPGRADE.txt
apps/app_queue.c
configs/queues.conf.sample

index e6c52bf..b6539d6 100644 (file)
@@ -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
index 092aa70..5beb4b5 100644 (file)
@@ -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) {
index ff00964..31aa245 100644 (file)
@@ -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
 ;