[asterisk-dev] app_queue, ringinuse, joinempty combination problems

Mark Michelson mmichelson at digium.com
Wed Jan 21 09:25:55 CST 2009

Wolfgang Pichler wrote:
> Hi all,
> i have a queue configured (realtime) with ringinuse=no and 
> joinempty=strict    (running asterisk
> What i wanted to achive with this is - when there are all queue members 
> already on the phone - then don't join the queue (and this should work 
> with this config options if i am not wrong)
> But calls will join the queue - regardless if there is a free member or not
> so i have taken a look at the code - function join_queue
> there you can read
>         /* This is our one */
>         stat = get_member_status(q, qe->max_penalty);
>         if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
>                 *reason = QUEUE_JOINEMPTY;
>         else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == 
>                 *reason = QUEUE_JOINUNAVAIL;
>         else if (q->maxlen && (q->count >= q->maxlen))
>                 *reason = QUEUE_FULL;
>         else {
>  - so when QUEUE_EMPTY_STRICT is set - and the get_member_status 
> function does return QUEUE_NO_REACHABLE_MEMBERS or QUEUE_NO_MEMBERS then 
> it will return with JOINUNAVAIL
> if i look at the get_member_status function - i can see the following
> static enum queue_member_status get_member_status(struct call_queue *q, 
> int max_penalty)
> {
>         struct member *member;
>         struct ao2_iterator mem_iter;
>         enum queue_member_status result = QUEUE_NO_MEMBERS;
>         ast_mutex_lock(&q->lock);
>         mem_iter = ao2_iterator_init(q->members, 0);
>         while ((member = ao2_iterator_next(&mem_iter))) {
>                 if (max_penalty && (member->penalty > max_penalty)) {
>                         ao2_ref(member, -1);
>                         continue;
>                 }
>                 if (member->paused) {
>                         ao2_ref(member, -1);
>                         continue;
>                 }
>                 switch (member->status) {
>                 case AST_DEVICE_INVALID:
>                         /* nothing to do */
>                         ao2_ref(member, -1);
>                         break;
>                 case AST_DEVICE_UNAVAILABLE:
>                         result = QUEUE_NO_REACHABLE_MEMBERS;
>                         ao2_ref(member, -1);
>                         break;
>                 default:
>                         ast_mutex_unlock(&q->lock);
>                         ao2_ref(member, -1);
>                         return QUEUE_NORMAL;
>                 }
>         }
>         ast_mutex_unlock(&q->lock);
>         return result;
> }
> it does handle corrent the min max penalty and the paused members. Also 
> if a member is unavailable or invalid it does not count the member as 
> available member - but it does ignore members which have an active call 
> (and ringinuse=yes - so the member has to get considered as unavailable) !!
> For me this seems to be wrong - what are you thinking about this ?
> I think adding something like this in the while loop before the switch 
> would make it handle it correct...
>         if (!q->ringinuse && (member->status != AST_DEVICE_NOT_INUSE) && 
> (member->status != AST_DEVICE_UNKNOWN)) {
>                         ao2_ref(member, -1);
>                         continue;
>         }
> regards,
> Wolfgang

Hi Wolfgang,

I can see where you're coming from here, because the queues.conf.sample file 
mentions that if all queue members are "unavailable" then the caller will not be 
able to join the queue if joinempty=strict is set. The problem is that what 
constitutes a member as "unavailable" is not well-defined in the queues.conf 
file. This corresponds to the device state value AST_DEVICE_UNAVAILABLE. This 
state is most typically used for Agent channels which are members of a queue but 
not logged in. By having joinempty=strict, the setting pretty much means to only 
allow a call to enter the queue if there is at least one unpaused member who is 
logged into the queue and whose penalty is below the maximum.

The ringinuse option really has no bearing on the joinempty option, and I would 
find it a bit odd if it did since they govern two separate operations of queues. 
  ringinuse only affects callers already in a queue, whereas joinempty is used 
to determine who can enter a queue in the first place. If there were a joinempty 
option which specified that "in use" members should be a reason not to join the 
queue, then that would be the way to go with this.

In Asterisk 1.4, there is no convenient way to do what you are trying to do, 
aside from patching the code as you have done. However, in Asterisk trunk the 
joinempty option has been modified immensely. In addition to allowing the old 
yes, no, strict, and loose options, joinempty also allows for a 
comma-separated-list of conditions to be used when testing for member 
availability so that you have much more fine-grained control over when a caller 
should or should not be allowed to join a queue. All of this information is 
specified in detail in the queues.conf.sample file in trunk.

Mark Michelson

More information about the asterisk-dev mailing list