]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[mod_callcenter] Fix stale agents and UUID broadcasts
authoryois615 <38441801+yois615@users.noreply.github.com>
Tue, 28 Mar 2023 11:53:16 +0000 (07:53 -0400)
committerGitHub <noreply@github.com>
Tue, 28 Mar 2023 11:53:16 +0000 (14:53 +0300)
* [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.

src/mod/applications/mod_callcenter/mod_callcenter.c

index fd7bb3dafab041e83c547147c710db489d84a323..b035b6d7f93d8b2eec50e2e322d7782e11a5931b 100644 (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))) {