Contents
Best Coding Practices
This chapter is for developers who are familiar with the Agent Interaction Services. It reviews the rules you would otherwise find throughout this book for developing a high-performance application on top of the Agent Interaction Services.
Introduction
When you develop an agent application on the Agent Interaction SDK Services API, observing a few basic rules will help optimize your application's performance in your production environment.
The Agent Interaction Services API is not a traditional API, and its service complexity is hidden behind the service interfaces. For instance, as detailed later in this chapter, calling the get methods reduces the code complexity but increases the network traffic.
This chapter is intended to help you make a few checks and corrections to your applications before you start testing them in production environments.
Avoid Wildcards
Although the Agent Interaction Services API includes wildcards to deal with with DTOs (see DTOs and Wildcards) or events (see Wildcards), they should be used for your application’s development only.
The * Wildcard
In a production-like environment, the * wildcard should be avoided if you want fast application responses. This wildcard is likely to disturb the network traffic and slow down your application’s performance, (since it usually retrieves wide data sets).
The default Wildcard
If you get more attributes than you need with the default wildcard, or, on the contrary, if the default wildcard does not retrieve enough attributes, you should instead specify the exact list of attributes that you need.
Note that the default wilcard can be use in production-like environment. The related attributes should not cause any performance issue.
No Wildcards
Get exactly what you need, neither more, nor less, so that your application can work without significantly increasing network activity.
Achieve the best performance for your application by removing all wildcards from your code before you start load-testing it.
Avoid This:
// Creating a topic event for voice media events
TopicsEvent voiceMediaTopicsEvent = new TopicsEvent();
voiceMediaTopicsEvent.eventName = "VoiceMediaEvent";
voiceMediaTopicsEvent.attributes = new String[]
{
"agent:*"
};
Do This:
// Creating a topic event for voice media events
TopicsEvent voiceMediaTopicsEvent = new TopicsEvent();
voiceMediaTopicsEvent.eventName = "VoiceMediaEvent";
voiceMediaTopicsEvent.attributes = new String[]
{
"agent:voiceMediaInfo",
"agent:dnActionsPossible"
};
Tips for Events Processing
A Single Subscriber
You need a single subscriber per client application. That is, a single instance of SubscriberResult for your application at runtime. Once it is created, you should use this reference for all your event subscriptions and un-subscriptions.
For details about how you get this instance, see Subscribing to the Events of a Service.
About Subscriptions
When you subscribe to a set of events (see Building TopicsEvent), it is important to register for the minimum number of attributes, because this data travels through the network each time that an event reports a modification. Given this, you should also design your application to modify subscriptions, asking for additional attributes only when needed.
About Notification
As a general guideline, to make sure that notification works fine:
-
Do not perform extensive event processing in the methods related to the notification.
-
Avoid calls to service methods during notification processing; these calls retrieve data through the network and slow down event publishing, and may even block it.
If you want to perform an extended treatment, or a treatment for making calls to services methods, be sure that your application implements this code in a separate thread.
Tips for DTOs
Guidelines
Each time you call a XxxService.getXxxDTO() or XxxService.setXxxDTO()
method, your application makes a server request. As a result, data travels through the network. Even if your application repeats an identical call to a XxxService.getXxxDTO() method, the request is repeated and, again, data travels through the network.
The Agent Interaction Services API does not cache data on the client’s side, and it does not keep any reference either. So, when you develop your application, you should take into account the cost of each server request.
For instance, if your application uses some agent data in an information panel, do not request agent DTOs each time that the user displays the panel. You are better off keeping a local variable and updating data with agent events.
You can also create a cache locally to save the network bandwidth. For instance, contact data does not often change, so your application could retrieve contact data at startup.
Additional Details
You may notice that some DTOs, methods, or attributes retrieve wide collections of objects or heavy data (such as binaries and attachments). When using items from Critical Areas, it is critical that you understand that their improper use can lead to significant increases in network traffic.
Service |
Methods, DTOs, or Attributes |
---|---|
IHistoryService
|
IHistoryService.getHistoryDTO()
|
ISRLService
|
StandardResponseDTO
|
IWorkflowService
|
workbin-interaction:attachedData
|
IInteraction
|
interaction:attachedData
|
IInteractionMailService
|
interaction.mail:attachments
|
Tips
-
When your application calls methods that retrieve wide collections of items (SRL, history, workflow, interactions), you can reduce network activity with pagination. For instance, when your application gets HistoryItems, set up a positive value for the length field of the InteractionSearchTemplate that you pass as an argument of the IHistory.getHistoryDTO() method.
-
When your application retrieves interactions lists, it should specify attribute names for ShortAttachment values instead of Attachment. Each ShortAttachment instance describes an Attachment and provides enough information to be useful for the user at first glance.Your application should request attachments only when the user explicitly asks for them.
Additional Information About Workbins
The IWorkbinService methods collect wide sets of interaction data, so use special care with attributes passed in as arguments. In particular, the getWorkbinsContentForAllDTO() method retrieves workbins for all agents and is very dangerous in regards to the number of interactions concerned and the list of attributes your application can ask for each of them.
Tips for High Availability
The Agent Interaction Services offer high availability embedded in the Genesys Integration Server. High availability is not your responsability, but you should take into account the following guidelines during the implementation of your application.
Voice Interactions in Specific Service Status
For voice interactions, NEW and RELEASED statuses are specific to the Agent Interaction Services. Interactions in these statuses do not exist in the T-Servers. So, after a switchover, it is impossible to recover them from the T-Servers and they are lost.
The following tips should help you avoid losing interactions.
Interactions in NEW Status
Interactions are assigned the NEW status when MakeCall is invoked in two steps, the first step being the interaction creation, the second being the dialing step. The solution is to use the one-step MakeCall in which the destination directory number (destDn) is provided:
InteractionVoiceErrorDTO err = interactionVoiceService.createInteractionFromDnDTO(
sourceDn , null , destDn ,null ,
MakeCallType.REGULAR , attachedData , null , null );
Interactions in RELEASE Status
Interactions are assigned the RELEASED status when T-Server releases them. At this point they still exist in the Agent Interaction Services to allow agents to add data and comments. These modifications are saved in the UCS database when your application calls the InteractionVoiceService.markDone() method.
In case of switchover, these interactions are lost and cannot be saved. To avoid losing comments, they should be saved before the call is released and your application should mark done the interaction as soon that the RELEASED event is received: interactionVoiceService.markDone(interactionId);
E-Mail and Open Media Interactions
In case of switchover, the outgoing e-mail and open media interactions are no longer associated with the agent’s Place. Thus, your application needs to call the InteractionService.openInteractionForPlaceDTO() method in order to retrieve these interactions and make them available for the agent.
Update Status
Your application should subscribe for the event sent to the event service. If your application’s subscriber changes its GIS node, this event’s attribute subscriber:isSubscriberChangeNode is set to true.
In this case, your application should retrieve data to update the status of agents, places and medias, and interactions as shown in the following code snippet.
if (event.serviceName.Equals("EventService")) {
bool isSubscriberChangeNode = false;
foreach( KeyValue attribute in event.attributes) {
if (attribute.key.equals("subscriber:isSubscriberChangeNode")) {
isSubscriberChangeNode = true;
}
}
if (isSubscriberChangeNode ) {
// open a window to signal the event to the agent
// update voice interactions
InteractionPlaceDTO[] interactions =
interactionService.getInteractionsDTOFromPlace(
new String[] { placeId }, new String[] {"default"} );
for (int i=0; interactions!= null && i < interactions.Length; i++) {
InteractionPlaceDTO ia = interactions[i];
for (int j=0; j < ia.interactionsDTO.Length; j++) {
InteractionDTO item = ia.interactionsDTO[j];
for (int k=0; k< item.data.Length; k++) {
String key = item.data[k].key;
Object obj = item.data[k].value;
//...
}
}
}
// update agent status
PersonDTO[] persons = agentService.getPersonsDTO(
new String[] { "smith" }, // agentId
new String[] {"agent:loggedDns", "agent:loggedMedias"} );
for (int i=0; persons!= null && i < persons.Length; i++) {
PersonDTO personDTO = persons[i];
if (personDTO.data.Length > 0) {
for (int j=0; j< personDTO.data.Length; j++) {
String key = personDTO.data[j].key;
if (key.Equals("agent:loggedDns")) {
VoiceMediaInfo[] voiceMediaInfos = (VoiceMediaInfo[])personDTO.data[j].value;
for (int k=0; k< voiceMediaInfos.Length; k++) {
VoiceMediaInfo voiceMediaInfo = voiceMediaInfos[k];
String dnId = voiceMediaInfo.dnId;
VoiceMediaStatus voiceMediaStatus = voiceMediaInfo.status; // NOT_READY READY ...
// update status
}
}
if (key.Equals("agent:loggedMedias")) {
MediaInfo[] mediaInfos = (MediaInfo[])personDTO.data[j].value;
for (int k=0; k< mediaInfos.Length; k++) {
MediaInfo mediaInfo = mediaInfos[k];
String mediaName = mediaInfo.name;
MediaStatus mediaStatus = mediaInfo.status; // NOT_READY READY ...
// update status
}
}