From: phoneben <67923255+phoneben@users.noreply.github.com> Date: Mon, 26 May 2025 20:52:34 +0000 (+0300) Subject: app_queue: queue rules – Add support for QUEUE_RAISE_PENALTY=rN to raise penalties... X-Git-Tag: 21.10.0-rc1~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aad714961399cd3180245be8b449b53e67bee41d;p=thirdparty%2Fasterisk.git app_queue: queue rules – Add support for QUEUE_RAISE_PENALTY=rN to raise penalties only for members within min/max range 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) --- diff --git a/apps/app_queue.c b/apps/app_queue.c index 3f76a3888e..1a2c6b37d4 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -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)); diff --git a/configs/samples/queuerules.conf.sample b/configs/samples/queuerules.conf.sample index b131f84c4f..0e2b40cb45 100644 --- a/configs/samples/queuerules.conf.sample +++ b/configs/samples/queuerules.conf.sample @@ -37,11 +37,14 @@ ; made during the caller's stay in the queue, these will not be reflected for that caller. ; ; The syntax for these rules is -; penaltychange => ,[,absolute or relative change to QUEUE_MIN_PENALTY][,absolute or relative change to QUEUE_RAISE_PENALTY] +; penaltychange => ,[,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