[Asterisk-code-review] res_queue: add option to connect agents only to longest waiting queue... (asterisk[master])

Nathan Bruning asteriskteam at digium.com
Tue Jan 24 07:56:43 CST 2023


Nathan Bruning has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/19793 )


Change subject: res_queue: add option to connect agents only to longest waiting queue caller
......................................................................

res_queue: add option to connect agents only to longest waiting queue caller

This adds an option 'force_longest_waiting_caller' which can be enabled per queue,
which changes the behavior of the queue engine to prevent queue callers from
'jumping ahead' when an agent is in multiple queues.

ASTERISK-17732 #close
ASTERISK-17570 #close

Change-Id: I4a8e4c21c60639c214114fc909226c175a8849f9
---
M apps/app_queue.c
M configs/samples/queues.conf.sample
A doc/CHANGES-staging/app_queue_force_longest_waiting_caller.txt
3 files changed, 94 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/93/19793/1

diff --git a/apps/app_queue.c b/apps/app_queue.c
index c5b7d10..15f40a5 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1606,6 +1606,9 @@
 /*! \brief queues.conf [general] option */
 static int log_membername_as_agent;
 
+/*! \brief queues.conf [general] option */
+static int force_longest_waiting_caller = 0;
+
 /*! \brief name of the ringinuse field in the realtime database */
 static char *realtime_ringinuse_field;
 
@@ -4535,6 +4538,56 @@
 	return found;
 }
 
+static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
+{
+	struct call_queue *q;
+	struct member *mem;
+	int is_longest_waiting = 1;
+	struct ao2_iterator queue_iter;
+	struct queue_ent *ch;
+
+	queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
+		if (q == caller->parent) { /* don't check myself, could deadlock */
+			queue_t_unref(q, "Done with iterator");
+			continue;
+		}
+		ao2_lock(q);
+		/*
+		 * If the other queue has equal weight, see if we should let that handle
+		 * their call first. If weights are not equal, compare_weights will step in.
+		 */
+		if (q->weight == caller->parent->weight && q->count && q->members) {
+			if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
+				ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
+				
+				/* Does this queue have a caller that's been waiting longer? */
+				ch = q->head;
+				while (ch) {
+					/* If ch->pending, the other call (which may be waiting for a longer period of time),
+					 * is already ringing at another agent. Ignore such callers; otherwise, all agents
+					 * will be unused until the first caller is picked up.
+					 */
+					if (ch->start < caller->start && !ch->pending) {
+						ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
+								  q->name, ch->pos, ch->start, caller->start);
+						is_longest_waiting = 0;
+						break;
+					}
+					ch = ch->next;
+				}
+			}
+		}
+		ao2_unlock(q);
+		queue_t_unref(q, "Done with iterator");
+		if (!is_longest_waiting) {
+			break;
+		}
+	}
+	ao2_iterator_destroy(&queue_iter);
+	return is_longest_waiting;
+}
+
 /*! \brief common hangup actions */
 static void do_hang(struct callattempt *o)
 {
@@ -4598,6 +4651,12 @@
 			qe->parent->name, call->interface);
 		return 0;
 	}
+	
+	if (force_longest_waiting_caller && !is_longest_waiting_caller(qe, memberp)) {
+		ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
+				  qe->parent->name, call->interface);
+		return 0;
+	}
 
 	if (!memberp->ringinuse) {
 		struct member *mem;
@@ -9433,6 +9492,10 @@
 	if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
 		log_membername_as_agent = ast_true(general_val);
 	}
+	force_longest_waiting_caller = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
+		force_longest_waiting_caller = ast_true(general_val);
+	}
 }
 
 /*! \brief reload information pertaining to a single member
diff --git a/configs/samples/queues.conf.sample b/configs/samples/queues.conf.sample
index 3b2c18b..09fe534 100644
--- a/configs/samples/queues.conf.sample
+++ b/configs/samples/queues.conf.sample
@@ -51,6 +51,14 @@
 ;
 ;log_membername_as_agent = no
 ;
+; force_longest_waiting_caller will cause app_queue to make sure callers are offered
+; in order (longest waiting first), even for callers across multiple queues.
+; Before a call is offered to an agent, an additional check is made to see if the agent
+; is a member of another queue with a call that's been waiting longer. If so, the current
+; call is not offered to the agent.
+;
+;force_longest_waiting_caller = no
+;
 ;[markq]
 ;
 ; A sample call queue
diff --git a/doc/CHANGES-staging/app_queue_force_longest_waiting_caller.txt b/doc/CHANGES-staging/app_queue_force_longest_waiting_caller.txt
new file mode 100644
index 0000000..f43c2a6
--- /dev/null
+++ b/doc/CHANGES-staging/app_queue_force_longest_waiting_caller.txt
@@ -0,0 +1,7 @@
+Subject: app_queue
+
+A new option named "force_longest_waiting_caller" has been added to be configured
+per queue. When enabled, the queue engine performs additional checks before connecting
+a caller to an agent, making sure that the caller is indeed the 'longest waiting caller'.
+When an agent is a member of multiple queues, this ensures more 'fair' behavior from the
+caller's perspective.
\ No newline at end of file

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/19793
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: I4a8e4c21c60639c214114fc909226c175a8849f9
Gerrit-Change-Number: 19793
Gerrit-PatchSet: 1
Gerrit-Owner: Nathan Bruning <nathan at iperity.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20230124/a01063e3/attachment.html>


More information about the asterisk-code-review mailing list