[asterisk-commits] mmichelson: branch mmichelson/queue-penalty r93947 - in /team/mmichelson/queu...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Dec 19 10:09:01 CST 2007


Author: mmichelson
Date: Wed Dec 19 10:09:01 2007
New Revision: 93947

URL: http://svn.digium.com/view/asterisk?view=rev&rev=93947
Log:
Introducing the brand new QUEUE_MIN_PENALTY channel variable! Why would you want this?
With the new penalty rules, you may wish to implement a sliding "window" of available
members. With this change, this is possible.

The insert_penaltychange code is a bit scatterbrained at this point...but it works!

Next step is to allow for a queue to use a different set of rules depending on an application
argument when Queue() is called.


Modified:
    team/mmichelson/queue-penalty/apps/app_queue.c
    team/mmichelson/queue-penalty/configs/queues.conf.sample
    team/mmichelson/queue-penalty/doc/tex/channelvariables.tex

Modified: team/mmichelson/queue-penalty/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/queue-penalty/apps/app_queue.c?view=diff&rev=93947&r1=93946&r2=93947
==============================================================================
--- team/mmichelson/queue-penalty/apps/app_queue.c (original)
+++ team/mmichelson/queue-penalty/apps/app_queue.c Wed Dec 19 10:09:01 2007
@@ -330,6 +330,7 @@
 	int handled;                           /*!< Whether our call was handled */
 	int pending;                           /*!< Non-zero if we are attempting to call a member */
 	int max_penalty;                       /*!< Limit the members that can take this call to this penalty or lower */
+	int min_penalty;                       /*!< Limit the members that can take this call to this penalty or higher */
 	int linpos;							   /*!< If using linear strategy, what position are we at? */
 	int linwrapped;						   /*!< Is the linpos wrapped? */
 	time_t start;                          /*!< When we started holding */
@@ -371,9 +372,11 @@
 #define QUEUE_EVENT_VARIABLES 3
 
 struct penalty_rule {
-	int time;							/*!< Number of seconds that need to pass before applying this rule */
-	int value;                          /*!< The amount specified in the penalty rule */
-	int relative;						/*!< Is this a relative amount? 1 for relative, 0 for absolute */
+	int time;                           /*!< Number of seconds that need to pass before applying this rule */
+	int max_value;                      /*!< The amount specified in the penalty rule for max penalty */
+	int min_value;                      /*!< The amount specified in the penalty rule for min penalty */
+	int max_relative;                   /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
+	int min_relative;                   /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
 	AST_LIST_ENTRY(penalty_rule) list;  /*!< Next penalty_rule */
 };
 
@@ -581,7 +584,7 @@
 	QUEUE_NORMAL
 };
 
-static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
+static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty, int min_penalty)
 {
 	struct member *member;
 	struct ao2_iterator mem_iter;
@@ -590,7 +593,7 @@
 	ao2_lock(q);
 	mem_iter = ao2_iterator_init(q->members, 0);
 	for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
-		if (max_penalty && (member->penalty > max_penalty))
+		if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty)))
 			continue;
 
 		switch (member->status) {
@@ -991,7 +994,7 @@
 
 static int insert_penaltychange (struct call_queue *q, const char *content, const int linenum)
 {
-	char *timestr, *changestr, *contentdup;
+	char *timestr, *maxstr, *minstr, *contentdup;
 	struct penalty_rule *rule = NULL, *iter;
 	int time, inserted = 0;
 
@@ -1001,17 +1004,17 @@
 	}
 
 	contentdup = ast_strdupa(content);
+	ast_log(LOG_DEBUG, "Analyzing entry %s on line %d...\n", contentdup, linenum);
 	
-	if (!(changestr = strchr(contentdup, ','))) {
+	if (!(maxstr = strchr(contentdup, ','))) {
 		ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
 		ast_free(rule);
 		return -1;
 	}
-	
-	*changestr++ = '\0';
+
+	*maxstr++ = '\0';
 	timestr = contentdup;
 
-	/*Let's get the number of seconds first...*/
 	if ((time = atoi(timestr)) < 0) {
 		ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
 		ast_free(rule);
@@ -1020,12 +1023,23 @@
 
 	rule->time = time;
 
-	/*Now on to the change*/
-	if (*changestr == '+' || *changestr == '-') {
-		rule->relative = 1;
-	}
-
-	rule->value = atoi(changestr); 
+	if ((minstr = strchr(maxstr,',')))
+		*minstr++ = '\0';
+	
+	/* The last check will evaluate true if either no penalty change is indicated for a given rule
+	 * OR if a min penalty change is indicated but no max penalty change is */
+	if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
+		rule->max_relative = 1;
+	}
+
+	rule->max_value = atoi(maxstr);
+
+	if (!ast_strlen_zero(minstr)) {
+		if (*minstr == '+' || *minstr == '-')
+			rule->min_relative = 1;
+		rule->min_value = atoi(minstr);
+	} else /*there was no minimum specified, so assume this means no change*/
+		rule->min_relative = 1;
 
 	/*We have the rule made, now we need to insert it where it belongs*/
 	ao2_lock(q);
@@ -1549,7 +1563,7 @@
 	ao2_lock(q);
 
 	/* This is our one */
-	stat = get_member_status(q, qe->max_penalty);
+	stat = get_member_status(q, qe->max_penalty, qe->min_penalty);
 	if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
 		*reason = QUEUE_JOINEMPTY;
 	else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS))
@@ -2596,7 +2610,7 @@
 			break;
 		}
 
-		stat = get_member_status(qe->parent, qe->max_penalty);
+		stat = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty);
 
 		/* leave the queue if no agents, if enabled */
 		if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
@@ -2632,15 +2646,23 @@
 		
 		/* see if we need to move to the next penalty level for this queue */
 		while (qe->pr && ((time(NULL) - qe->start) > qe->pr->time)) {
-			int max_penalty = qe->pr->relative ? qe->max_penalty + qe->pr->value : qe->pr->value;
-			char max_penalty_str[12]; /*XXX Will change this idiom and probably optimize things once everything is running */
+			int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
+			int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value;
+			char max_penalty_str[12], min_penalty_str[12]; /*XXX Will change this idiom and probably optimize things once everything is running */
 			/* a relative change to the penalty could put it below 0 */
 			if (max_penalty < 0)
 				max_penalty = 0;
+			if (min_penalty < 0)
+				min_penalty = 0;
+			if (min_penalty > max_penalty)
+				min_penalty = max_penalty;
 			snprintf(max_penalty_str, sizeof(max_penalty_str) - 1, "%d", max_penalty);
+			snprintf(min_penalty_str, sizeof(min_penalty_str) - 1, "%d", min_penalty);
 			pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
+			pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
 			qe->max_penalty = max_penalty;
-			ast_log(LOG_DEBUG, "Set max penalty for caller %s to %d\n", qe->chan->name, qe->max_penalty);
+			qe->min_penalty = min_penalty;
+			ast_log(LOG_DEBUG, "Set max penalty to %d and min penalty to %d for caller %s\n", qe->max_penalty, qe->min_penalty, qe->chan->name);
 			qe->pr = AST_LIST_NEXT(qe->pr, list);
 		}
 
@@ -2692,7 +2714,7 @@
 
 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 {
-	if (qe->max_penalty && (mem->penalty > qe->max_penalty))
+	if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty)))
 		return -1;
 
 	switch (q->strategy) {
@@ -4042,8 +4064,10 @@
 	AST_LIST_TRAVERSE(&qe->parent->rules, pr_iter, list) {
 		struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
 		new_pr->time = pr_iter->time;
-		new_pr->value = pr_iter->value;
-		new_pr->relative = pr_iter->relative;
+		new_pr->max_value = pr_iter->max_value;
+		new_pr->min_value = pr_iter->min_value;
+		new_pr->max_relative = pr_iter->max_relative;
+		new_pr->min_relative = pr_iter->min_relative;
 		AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
 	}
 	ao2_unlock(qe->parent);
@@ -4055,9 +4079,10 @@
 	int ringing=0;
 	const char *user_priority;
 	const char *max_penalty_str;
+	const char *min_penalty_str;
 	int prio;
 	int qcontinue = 0;
-	int max_penalty;
+	int max_penalty, min_penalty;
 	enum queue_result reason = QUEUE_UNKNOWN;
 	/* whether to exit Queue application after the timeout hits */
 	int tries = 0;
@@ -4124,6 +4149,18 @@
 		max_penalty = 0;
 	}
 
+	if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
+		if (sscanf(min_penalty_str, "%d", &min_penalty) == 1) {
+			ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
+		} else {
+			ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
+				min_penalty_str, chan->name);
+			min_penalty = 0;
+		}
+	} else {
+		min_penalty = 0;
+	}
+
 	if (args.options && (strchr(args.options, 'r')))
 		ringing = 1;
 
@@ -4136,6 +4173,7 @@
 	qe.chan = chan;
 	qe.prio = prio;
 	qe.max_penalty = max_penalty;
+	qe.min_penalty = min_penalty;
 	qe.last_pos_said = 0;
 	qe.last_pos = 0;
 	qe.last_periodic_announce_time = time(NULL);
@@ -4198,7 +4236,7 @@
 				goto stop;
 			}
 
-			stat = get_member_status(qe.parent, qe.max_penalty);
+			stat = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty);
 
 			/* exit after 'timeout' cycle if 'n' option enabled */
 			if (noption && tries >= qe.parent->membercount) {
@@ -4245,15 +4283,23 @@
 
 			/* see if we need to move to the next penalty level for this queue */
 			while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
-				char max_penalty_str[12]; /*XXX Will change this idiom and probably optimize things once everything is running */
-				max_penalty = qe.pr->relative ? qe.max_penalty + qe.pr->value : qe.pr->value;
+				char max_penalty_str[12], min_penalty_str[12]; /*XXX Will change this idiom and probably optimize things once everything is running */
+				max_penalty = qe.pr->max_relative ? qe.max_penalty + qe.pr->max_value : qe.pr->max_value;
+				min_penalty = qe.pr->min_relative ? qe.min_penalty + qe.pr->min_value : qe.pr->min_value;
 				/* A relative change could put the max_penalty below 0 */
 				if (max_penalty < 0)
 					max_penalty = 0;
+				if (min_penalty < 0)
+					min_penalty = 0;
+				if (min_penalty > max_penalty)
+					min_penalty = max_penalty;
 				snprintf(max_penalty_str, sizeof(max_penalty_str) - 1, "%d", max_penalty);
+				snprintf(min_penalty_str, sizeof(min_penalty_str) - 1, "%d", min_penalty);
 				pbx_builtin_setvar_helper(qe.chan, "QUEUE_MAX_PENALTY", max_penalty_str);
+				pbx_builtin_setvar_helper(qe.chan, "QUEUE_MAX_PENALTY", min_penalty_str);
 				qe.max_penalty = max_penalty;
-				ast_log(LOG_DEBUG, "Changed the max penalty for caller %s to %d\n", qe.chan->name, qe.max_penalty);
+				qe.min_penalty = min_penalty;
+				ast_log(LOG_DEBUG, "Changed the max penalty to %d and the min penalty to %d for caller %s since %d seconds have elapsed\n", qe.max_penalty, qe.min_penalty, qe.chan->name, qe.pr->time);
 				qe.pr = AST_LIST_NEXT(qe.pr, list);
 			}
 

Modified: team/mmichelson/queue-penalty/configs/queues.conf.sample
URL: http://svn.digium.com/view/asterisk/team/mmichelson/queue-penalty/configs/queues.conf.sample?view=diff&rev=93947&r1=93946&r2=93947
==============================================================================
--- team/mmichelson/queue-penalty/configs/queues.conf.sample (original)
+++ team/mmichelson/queue-penalty/configs/queues.conf.sample Wed Dec 19 10:09:01 2007
@@ -362,21 +362,22 @@
 ;
 ; timeoutrestart = no
 ;
-; It is possible to change the value of QUEUE_MAX_PENALTY channel variable in
-; mid-call by defining rules in the queue for when to do so. This can allow for
-; a call to be opened to more members. The advantage to changing members this way
-; as opposed to inserting the caller into a different queue with more members or reinserting
-; the caller into the same queue with a different QUEUE_MAX_PENALTY set is that
-; the caller does not lose his place in the queue. Note: There is a limitation to these
-; rules; a caller will follow the penaltychange rules for the queue that were defined
-; at the time the caller entered the queue. If an update to the rules is made during the
-; the caller's stay in the queue, these will not be reflected for that caller.
+; It is possible to change the value of the QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY 
+; channel variables in mid-call by defining rules in the queue for when to do so. This can allow for
+; a call to be opened to more members or potentially a different set of members. 
+; The advantage to changing members this way as opposed to inserting the caller into a 
+; different queue with more members or reinserting the caller into the same queue with a different 
+; QUEUE_MAX_PENALTY or QUEUE_MIN_PENALTY set is that the caller does not lose his place in the queue. 
+; Note: There is a limitation to these rules; a caller will follow the penaltychange rules for 
+; the queue that were defined at the time the caller entered the queue. If an update to the rules is 
+; made during the the caller's stay in the queue, these will not be reflected for that caller.
 ;
 ; The syntax for these rules is
-; penaltychange => <number of seconds into the call>,<absolute or relative change to QUEUE_MAX_PENALTY>
-;
-; penaltychange => 30,+3 ; 30 seconds into the call increase the QUEUE_MAX_PENALTY by 3
-; penaltychange => 60,10 ; 60 seconds into the call increase the QUEUE_MAX_PENALTY to 10
+; penaltychange => <number of seconds into the call>,<absolute or relative change to QUEUE_MAX_PENALTY>[,absolute or relative change to QUEUE_MIN_PENALTY]
+;
+; penaltychange => 30,+3   ; 30 seconds into the call increase the QUEUE_MAX_PENALTY by 3, no change to QUEUE_MIN_PENALTY
+; penaltychange => 60,10,5 ; 60 seconds into the call increase the QUEUE_MAX_PENALTY to 10 and increase the QUEUE_MIN_PENALTY to 5
+; penaltychange => 75,,7   ; 75 seconds into the call keep the QUEUE_MAX_PENALTY the same and increase the QUEUE_MIN_PENALTY to 7
 ;
 ; Each member of this call queue is listed on a separate line in
 ; the form technology/dialstring.  "member" means a normal member of a

Modified: team/mmichelson/queue-penalty/doc/tex/channelvariables.tex
URL: http://svn.digium.com/view/asterisk/team/mmichelson/queue-penalty/doc/tex/channelvariables.tex?view=diff&rev=93947&r1=93946&r2=93947
==============================================================================
--- team/mmichelson/queue-penalty/doc/tex/channelvariables.tex (original)
+++ team/mmichelson/queue-penalty/doc/tex/channelvariables.tex Wed Dec 19 10:09:01 2007
@@ -826,6 +826,7 @@
 ${MONITOR_FILENAME}       File for monitoring (recording) calls in queue
 ${QUEUE_PRIO}             Queue priority
 ${QUEUE_MAX_PENALTY}      Maximum member penalty allowed to answer caller
+${QUEUE_MIN_PENALTY}      Minimum member penalty allowed to answer caller
 ${QUEUESTATUS}            Status of the call, one of:
                           (TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL)
 ${RECORDED_FILE}        * Recorded file in record()




More information about the asterisk-commits mailing list