]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
app_queue: queue rules – Add support for QUEUE_RAISE_PENALTY=rN to raise penalties...
authorphoneben <67923255+phoneben@users.noreply.github.com>
Mon, 26 May 2025 20:52:34 +0000 (23:52 +0300)
committerGeorge Joseph <gjoseph@sangoma.com>
Thu, 26 Jun 2025 18:15:05 +0000 (12:15 -0600)
This update adds support for a new QUEUE_RAISE_PENALTY format: rN

When QUEUE_RAISE_PENALTY is set to rN (e.g., r4), only members whose current penalty
is greater than or equal to the defined min_penalty and less than or equal to max_penalty
will have their penalty raised to N.

Members with penalties outside the min/max range remain unchanged.

Example behaviors:

QUEUE_RAISE_PENALTY=4     → Raise all members with penalty < 4 (existing behavior)
QUEUE_RAISE_PENALTY=r4    → Raise only members with penalty in [min_penalty, max_penalty] to 4

Implementation details:

Adds parsing logic to detect the r prefix and sets the raise_respect_min flag

Modifies the raise logic to skip members outside the defined penalty range when the flag is active

UserNote: This change introduces QUEUE_RAISE_PENALTY=rN, allowing selective penalty raises
only for members whose current penalty is within the [min_penalty, max_penalty] range.
Members with lower or higher penalties are unaffected.
This behavior is backward-compatible with existing queue rule configurations.

(cherry picked from commit 12440d232fea6970250381b408982b9a6e4c9ff2)

apps/app_queue.c
configs/samples/queuerules.conf.sample

index 3f76a3888e309958f39c1c246901a278a415f875..1a2c6b37d450b4d6b11e17e853b277e6d9174c41 100644 (file)
@@ -1880,6 +1880,7 @@ struct queue_ent {
        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 raise_penalty;                     /*!< Float lower penalty members to a minimum penalty */
+       int raise_respect_min;                 /*!< A switch raise_penalty should respect min_penalty not just max_penalty */
        int linpos;                            /*!< If using linear strategy, what position are we at? */
        int linwrapped;                        /*!< Is the linpos wrapped? */
        time_t start;                          /*!< When we started holding */
@@ -1950,6 +1951,7 @@ struct penalty_rule {
        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 */
        int raise_relative;                   /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
+       int raise_respect_min;                 /*!< A switch raise_penalty should respect min_penalty not just max_penalty */
        AST_LIST_ENTRY(penalty_rule) list;  /*!< Next penalty_rule */
 };
 
@@ -2589,7 +2591,7 @@ static struct ast_json *queue_member_blob_create(struct call_queue *q, struct me
  * is available, the function immediately returns 0. If no members are available,
  * then -1 is returned.
  */
-static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
+static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate, int raise_respect_min)
 {
        struct member *member;
        struct ao2_iterator mem_iter;
@@ -2599,8 +2601,13 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena
        for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
                int penalty = member->penalty;
                if (raise_penalty != INT_MAX && penalty < raise_penalty) {
-                       ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
-                       penalty = raise_penalty;
+                       /* Check if we should respect minimum penalty threshold */
+                       if (raise_respect_min && penalty < min_penalty) {
+                               ast_debug(4, "%s penalty %d not raised (below min %d)\n", member->membername, penalty, min_penalty);
+                       } else {
+                               ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
+                               penalty = raise_penalty;
+                       }
                }
                if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
                        if (conditions & QUEUE_EMPTY_PENALTY) {
@@ -2667,7 +2674,7 @@ static int get_member_status(struct call_queue *q, int max_penalty, int min_pena
 
        if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
                /* member state still may be RINGING due to lag in event message - check again with device state */
-               return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1);
+               return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1, raise_respect_min);
        }
        return -1;
 }
@@ -3306,6 +3313,11 @@ static int insert_penaltychange(const char *list_name, const char *content, cons
        }
 
        if (!ast_strlen_zero(raisestr)) {
+               rule->raise_respect_min = 0;  /* Initialize to 0 */
+               if (*raisestr == 'r') {
+                       rule->raise_respect_min = 1;               /* Set the flag */
+                       raisestr++;
+               }
                if (*raisestr == '+' || *raisestr == '-') {
                        rule->raise_relative = 1;
                }
@@ -3425,12 +3437,22 @@ static int load_realtime_rules(void)
                        }
                }
                if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
-                       ast_strlen_zero(raisestr) || sscanf(raisestr, "%30d", &raise_penalty) != 1) {
+                       ast_strlen_zero(raisestr) ) {
                        raise_penalty = 0;
                        raise_relative = 1;
                } else {
+                       if (*raisestr == 'r') {
+                               new_penalty_rule->raise_respect_min = 1;
+                               raisestr++;
+                       } else {
+                               new_penalty_rule->raise_respect_min = 0;
+                       }
                        if (*raisestr == '+' || *raisestr == '-') {
                                raise_relative = 1;
+                       } 
+                       if (sscanf(raisestr, "%30d", &raise_penalty) != 1) {
+                               raise_penalty = 0;
+                               raise_relative = 1;
                        }
                }
                new_penalty_rule->time = penaltychangetime;
@@ -4242,7 +4264,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
        /* This is our one */
        if (q->joinempty) {
                int status = 0;
-               if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) {
+               if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0, qe->raise_respect_min))) {
                        *reason = QUEUE_JOINEMPTY;
                        ao2_unlock(q);
                        queue_t_unref(q, "Done with realtime queue");
@@ -6078,7 +6100,7 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r
                if (qe->parent->leavewhenempty) {
                        int status = 0;
 
-                       if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->raise_penalty, qe->parent->leavewhenempty, 0))) {
+                       if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->raise_penalty, qe->parent->leavewhenempty, 0, qe->raise_respect_min))) {
                                record_abandoned(qe);
                                *reason = QUEUE_LEAVEEMPTY;
                                ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
@@ -8815,8 +8837,14 @@ static int queue_exec(struct ast_channel *chan, const char *data)
        }
 
        if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
+                if (*raise_penalty_str == 'r') {
+                       qe.raise_respect_min = 1;
+                       raise_penalty_str++;
+               } else {
+                       qe.raise_respect_min = 0;
+               }
                if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
-                       ast_debug(1, "%s: Got raise penalty %d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), raise_penalty);
+                       ast_debug(1, "%s: Got raise penalty %s%d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), qe.raise_respect_min ? "r" : "", raise_penalty);
                } else {
                        ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
                                raise_penalty_str, ast_channel_name(chan));
@@ -9008,7 +9036,7 @@ check_turns:
 
                if (qe.parent->leavewhenempty) {
                        int status = 0;
-                       if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.raise_penalty, qe.parent->leavewhenempty, 0))) {
+                       if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.raise_penalty, qe.parent->leavewhenempty, 0, qe.raise_respect_min))) {
                                record_abandoned(&qe);
                                reason = QUEUE_LEAVEEMPTY;
                                ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
index b131f84c4fd737f03d55ca9665c14b7dcf7bf073..0e2b40cb451e2cc4928fadfca49cd606fec36860 100644 (file)
 ; made during 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>[,absolute or relative change to QUEUE_MIN_PENALTY][,absolute or relative change to QUEUE_RAISE_PENALTY]
+; penaltychange => <number of seconds into the call>,<absolute or relative change to QUEUE_MAX_PENALTY>[,absolute or relative change to QUEUE_MIN_PENALTY][,absolute or relative change to QUEUE_RAISE_PENALTY or rN>]
 ;
+; - If QUEUE_RAISE_PENALTY is set to rN (e.g., r20), only agents with penalty between QUEUE_MIN_PENALTY and QUEUE_MAX_PENALTY (inclusive)
+;  will have their penalty raised to N. Others remain unchanged.
 ; Example:
 ; [myrule]
 ; 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
 ; penaltychange => 90,,,20 ; 90 seconds into the call leave QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY untouched and set QUEUE_RAISE_PENALTY to 20
+; penaltychange => 120,5,3,r20 ; After 120 seconds, set max=5, min=3, and raise only agents with penalty 3–5 to 20