[mod_callcenter] Fix stale agents and UUID broadcasts

* [call_center] Stop uuid_broadcast on answer

* [mod_callcenter] Fix stale members in database

When a channel is originated to an agent but the
member fails to bridge to that agent, the database is
not updated with the member status and a stale entry
of 'Answered' persists until mod_callcenter is restarted.

Additionally, cc_agent_found is set before the bridge,
therefore ending the while loop on the member channel.
If there is a problem with the agent bridge, the call is
terminated prematurely.

In this commit, we:

* Move the SQL update of the member
to the 'Answered' state to the agent thread instead of
the member's thread, so that correct data is populated.

* Reset the members state accordingly to Abandoned or
Waiting if the channels fail to bridge.

* Use cc_agent_bridged to end the member loop,
so that a member is put back on queue if the agent
channel fails to bridge.
This commit is contained in:
yois615 2023-03-28 07:53:16 -04:00 committed by GitHub
parent 965e88a6b0
commit 6d65f8e08c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 28 additions and 13 deletions

View File

@ -1969,9 +1969,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
playback_array(agent_session, o_announce);
}
/* This is used for the waiting caller to quit waiting for a agent */
/* This is used to set the reason for callcenter_function breakout */
switch_channel_set_variable(member_channel, "cc_agent_found", "true");
switch_channel_set_variable(member_channel, "cc_agent_uuid", agent_uuid);
if (switch_true(switch_channel_get_variable(member_channel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE)) || switch_true(switch_channel_get_variable(agent_channel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE))) {
switch_channel_set_flag(member_channel, CF_BYPASS_MEDIA_AFTER_BRIDGE);
}
@ -1990,6 +1991,12 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_channel_set_variable(agent_channel, "cc_agent_bridged", "false");
switch_channel_set_variable(member_channel, "cc_agent_bridged", "false");
/* Set member to Abandoned state, previous Trying */
sql = switch_mprintf("UPDATE members SET state = '%q', session_uuid = '', abandoned_epoch = '%" SWITCH_TIME_T_FMT "' WHERE uuid = '%q' AND instance_id = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), local_epoch_time_now(NULL), h->member_uuid, globals.cc_instance_id);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
if ((o_announce = switch_channel_get_variable(member_channel, "cc_bridge_failed_outbound_announce"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Playing bridge failed audio to agent %s, audio: %s\n", h->agent_name, o_announce);
playback_array(agent_session, o_announce);
@ -2008,9 +2015,15 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
bridged = 1;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member \"%s\" %s is bridged to agent %s\n",
h->member_cid_name, h->member_cid_number, h->agent_name);
switch_channel_set_variable(member_channel, "cc_agent_bridged", "true");
switch_channel_set_variable(agent_channel, "cc_agent_bridged", "true");
switch_channel_set_variable(member_channel, "cc_agent_uuid", agent_uuid);
/* Update member to Answered state, previous Trying */
sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%" SWITCH_TIME_T_FMT "' WHERE uuid = '%q' AND instance_id = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ANSWERED), local_epoch_time_now(NULL), h->member_uuid, globals.cc_instance_id);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
}
if (bridged) {
@ -2111,7 +2124,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
}
} else {
/* Agent didn't answer or originate failed */
/* Agent didn't answer or originate/bridge failed */
int delay_next_agent_call = 0;
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
switch_channel_clear_app_flag_key(CC_APP_KEY, member_channel, CC_APP_AGENT_CONNECTING);
@ -3051,6 +3064,10 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_channel_set_variable(member_channel, "cc_side", "member");
switch_channel_set_variable(member_channel, "cc_member_uuid", member_uuid);
/* Clear flags in case previously set */
switch_channel_set_variable(member_channel, "cc_agent_found", NULL);
switch_channel_set_variable(member_channel, "cc_agent_bridged", NULL);
/* Add manually imported score */
if (cc_base_score) {
cc_base_score_int += atoi(cc_base_score);
@ -3178,8 +3195,8 @@ SWITCH_STANDARD_APP(callcenter_function)
args.buf = (void *) &ht;
args.buflen = sizeof(h);
/* An agent was found, time to exit and let the bridge do it job */
if ((p = switch_channel_get_variable(member_channel, "cc_agent_found")) && (agent_found = switch_true(p))) {
/* If the bridge didn't break the loop, break out now */
if ((p = switch_channel_get_variable(member_channel, "cc_agent_bridged")) && (agent_found = switch_true(p))) {
break;
}
/* If the member thread set a different reason, we monitor it so we can quit the wait */
@ -3201,8 +3218,6 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_channel_set_variable(member_channel, "cc_exit_key", buf);
h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_EXIT_WITH_KEY;
break;
} else if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
} else {
switch_status_t status = switch_ivr_collect_digits_callback(member_session, &args, 0, 0);
@ -3230,12 +3245,18 @@ SWITCH_STANDARD_APP(callcenter_function)
h->running = 0;
}
/* Stop uuid_broadcasts */
switch_core_session_flush_private_events(member_session);
switch_channel_stop_broadcast(member_channel);
switch_channel_set_flag_value(member_channel, CF_BREAK, 2);
/* Check if we were removed because FS Core(BREAK) asked us to */
if (h->member_cancel_reason == CC_MEMBER_CANCEL_REASON_NONE && !agent_found) {
h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_BREAK_OUT;
}
switch_channel_set_variable(member_channel, "cc_agent_found", NULL);
/* Canceled for some reason */
if (!switch_channel_up(member_channel) || h->member_cancel_reason != CC_MEMBER_CANCEL_REASON_NONE) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> abandoned waiting in queue %s\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), queue_name);
@ -3282,12 +3303,6 @@ SWITCH_STANDARD_APP(callcenter_function)
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Member %s <%s> is answered by an agent in queue %s\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), queue_name);
/* Update member state */
sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%" SWITCH_TIME_T_FMT "' WHERE uuid = '%q' AND instance_id = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ANSWERED), local_epoch_time_now(NULL), member_uuid, globals.cc_instance_id);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
/* Update some channel variables for xml_cdr needs */
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered");
if ((queue = get_queue(queue_name))) {