Skip to content
This repository was archived by the owner on May 2, 2023. It is now read-only.

Commit d25f32a

Browse files
authored
Update README.md to include success and failure events details (#126)
1 parent 2cbd3a0 commit d25f32a

File tree

2 files changed

+316
-15
lines changed

2 files changed

+316
-15
lines changed

README.md

Lines changed: 99 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ Each agent has an agentId that must be passed to subsequent requests. This is ma
153153
- [generateURLForDownloadFile](#generateurlfordownloadfile)
154154
- [generateURLForUploadFile](#generateurlforuploadfile)
155155
- [publishEvent](#publishevent)
156-
- [reconnect](#reconnect)
156+
- [connect](#connectcallback)
157+
- [reconnect](#reconnectskiptokengeneration)
158+
- [getBearerToken](#getbearertoken)
159+
- [refreshSession](#refreshsession)
160+
- [startPeriodicRefreshSession](#startperiodicrefreshsession)
157161
- [dispose](#dispose)
158162

159163
#### General request signature
@@ -772,6 +776,22 @@ agent.publishEvent({
772776
Success response:
773777
`{"sequence":32}`
774778
779+
#### connect(callback)
780+
This function should be called in the first stage of an agent lifecycle, or when an agent is disposed.
781+
782+
If you happen to call [dispose](#dispose), but you want to re-connect the agent again, use this function.
783+
784+
This method requires you to provide a callback function to check if an error is encountered.
785+
786+
An example would be:
787+
```javascript
788+
agent.connect((err) => {
789+
if (err) {
790+
console.error('An error occurred while connecting agent.', err);
791+
}
792+
});
793+
```
794+
775795
#### reconnect(skipTokenGeneration)
776796
**Make sure that you implement reconnect logic according to [liveperson's retry policy guidelines](https://developers.liveperson.com/guides-retry-policy.html)**
777797
@@ -783,6 +803,28 @@ Call `reconnect` on `error` with code `401`.
783803
784804
**Note**: When the `reconnect` method fails to re-establish a connection with LiveEngage, a `closed` and `error` events will fire. Unless these events are handled, multiple instances of a reconnection mechanism will be triggered. See our (retry policy)[https://developers.liveperson.com/retry-and-keepalive-best-practices-overview.html] for more information on how we recommend you handle a retry mechanism.
785805
806+
#### getBearerToken()
807+
After you connect an agent successfully, you may use this method to get the bearer token of an agent to call other APIs within LivePerson services.
808+
809+
#### refreshSession(callback)
810+
Use this method to prolong the session of the agent. In another note, this method prolongs the lifetime of the bearer token.
811+
812+
This method requires you to provide a callback function to check if an error is encountered.
813+
814+
An example would be:
815+
```javascript
816+
agent.refreshSession((err) => {
817+
if (err) {
818+
console.error('An error occurred while refreshing agent session.', err);
819+
}
820+
});
821+
```
822+
823+
### startPeriodicRefreshSession()
824+
Use this method to restart the refreshSession periodic calls to make sure that the bearer token is valid forever.
825+
826+
This method will also be called when you reconnect with token generation.
827+
786828
#### dispose()
787829
Will dispose of the connection and unregister internal events.
788830
@@ -1303,34 +1345,52 @@ agent.on('notification', body => {});
13031345
```
13041346
13051347
#### closed
1306-
This event fires when the socket is closed. If the reason is code 4401 or 4407 this indicates an authentication issue, so when you call [reconnect()](#reconnect(skiptokengeneration)) you should make sure not to pass the `skipTokenGeneration` argument.
1348+
This event fires when the socket is closed. If the reason is code 4401, 4407, or 1011 this indicates an authentication issue, so when you call [reconnect()](#reconnect(skiptokengeneration)) you should make sure not to pass the `skipTokenGeneration` argument.
1349+
1350+
In any other case, please make sure to [reconnect()](#reconnect(skiptokengeneration)) with passing the skipTokenGeneration flag set to true to avoid token re-generation.
13071351
13081352
This event will only occur once, so if you want to attempt to reconnect repeatedly you should initiate a periodic reconnect attempt here. **LivePerson recommends that you make periodic reconnect attempts at increasing intervals up to a finite number of attempts in order to prevent flooding our service and being blocked as a potentially abusive client**. See [LivePerson's retry policy guidelines](https://developers.liveperson.com/guides-retry-policy.html) for more information.
13091353
13101354
In the sample below we attempt to reconnect 35 times, waiting 5 seconds the first time and increasing the interval by a factor of 1.25 between each attempt.
13111355
1312-
Sample code:
1356+
#### Reconnect with Retry
1357+
13131358
```javascript
13141359
const reconnectInterval = 5; // in seconds
13151360
const reconnectAttempts = 35;
13161361
const reconnectRatio = 1.25; // ratio in the geometric series used to determine reconnect exponential back-off
13171362
1363+
agent._reconnect = (skipTokenGeneration, delay = reconnectInterval, attempt = 1) => {
1364+
agent._retryConnection = setTimeout(() => {
1365+
agent.reconnect(skipTokenGeneration);
1366+
if (++attempt <= reconnectAttempts) { agent._reconnect(delay * reconnectRatio, attempt) }
1367+
}, delay * 1000)
1368+
}
1369+
```
1370+
1371+
#### Sample Retry Logic
1372+
1373+
```javascript
13181374
// on connected cancel any retry interval remaining from reconnect attempt
13191375
agent.on('connected', () => {
13201376
clearTimeout(agent._retryConnection);
13211377
// etc etc
13221378
});
13231379
1324-
agent.on('closed', () => {
1325-
agent._reconnect(); // call our reconnect looper
1380+
agent.on('closed', (data) => {
1381+
switch (data) {
1382+
// Authentication issue
1383+
case 4401:
1384+
case 4407:
1385+
case 1011:
1386+
agent._reconnect(); // call our reconnect looper
1387+
break;
1388+
// Non-authentication issue
1389+
default:
1390+
agent._reconnect(true); // call our reconnect looper without token generation
1391+
break;
1392+
}
13261393
});
1327-
1328-
agent._reconnect = (delay = reconnectInterval, attempt = 1) => {
1329-
agent._retryConnection = setTimeout(()=>{
1330-
agent.reconnect();
1331-
if (++attempt <= reconnectAttempts) { agent._reconnect(delay * reconnectRatio, attempt) }
1332-
}, delay * 1000)
1333-
}
13341394
```
13351395
13361396
Example payload:
@@ -1339,13 +1399,36 @@ Example payload:
13391399
```
13401400
13411401
#### error
1342-
This event fires when the SDK receives an error from the messaging service. If you receive a `401` error you should [reconnect()](#reconnect) according to the [retry policy guidelines](https://developers.liveperson.com/guides-retry-policy.html) mentioned above, in the [closed](#closed) section.
1402+
This event fires when the SDK receives an error from the messaging service. There are two parameters that are passed in to the event.
1403+
1404+
* error:
1405+
1406+
```javascript
1407+
// The SDKError object
1408+
{
1409+
message: 'the message of the error',
1410+
code: 401, // Error code if the error actually comes from a network call (such as a REST API invocation)
1411+
error: Error // The original error object if it comes from another error that is not caused by a network call
1412+
}
1413+
```
1414+
1415+
* context:
1416+
```javascript
1417+
{
1418+
location: 'Event#Source' // The source location of the event, for example 'Reconnect#Login', which happens during the login section of the reconnect function
1419+
}
1420+
```
1421+
1422+
For more information of the Context object and what to do in times of failures, please visit [Success and Error Events](./README_success_and_error_events.md).
1423+
1424+
If you receive a `401` error you should [reconnect()](#reconnect) according to the [retry policy guidelines](https://developers.liveperson.com/guides-retry-policy.html) mentioned above, in the [closed](#closed) section.
13431425
13441426
Sample code:
13451427
```javascript
1346-
agent.on('error', err => {
1428+
agent.on('error', (err, context) => {
13471429
if (err && err.code === 401) {
1348-
agent._reconnect(); // agent._reconnect() defined in the on('closed',() => {}) example above.
1430+
agent._reconnect(); // The reconnect function defined in the closed section above.
1431+
// This will re-connect the WS connection and re-generate the bearer token
13491432
}
13501433
});
13511434
```
@@ -1355,6 +1438,7 @@ Example payload:
13551438
{"code":"ENOTFOUND","errno":"ENOTFOUND","syscall":"getaddrinfo","hostname":"va.agentvep.liveperson.net","host":"va.agentvep.liveperson.net","port":443}
13561439
```
13571440
1441+
13581442
### Deprecation notices
13591443
13601444
##### MessagingEventNotification isMe() - *deprecated*

README_success_and_error_events.md

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# Success and Error Events
2+
3+
4+
Node Agent SDK emits events when a flow succeeds or fails. These events will be useful in determining action items to take, as well as giving visibility about a particular flow in the SDK.
5+
6+
For example, you might want to have some metrics that keep track of how many times 'RefreshSession#Login' flow fails vs succeeding.
7+
8+
9+
## Success
10+
11+
Success events provide you with a parameter called context:
12+
13+
```javascript
14+
{
15+
location: 'Event#Source' // The source location of the event, for example 'Reconnect#Login',
16+
// which happens during the login section of the reconnect function
17+
}
18+
```
19+
20+
An example of implementation on putting a metric on the success events would be:
21+
22+
```javascript
23+
agent.on('success', (context) => {
24+
metricsInterface.countSuccess(context.location, 1);
25+
});
26+
```
27+
28+
## Error
29+
30+
There are two parameters that are passed in to the error event.
31+
32+
* error:
33+
34+
```javascript
35+
// The SDKError object that centralizes the error sources across the SDK
36+
{
37+
message: 'the message of the error',
38+
code: 401, // Error code if the error actually comes from a network call (such as a REST API invocation)
39+
error: Error // The original error object if it comes from another error
40+
}
41+
```
42+
43+
* context:
44+
```javascript
45+
{
46+
location: 'Event#Source' // The source location of the event, for example 'Reconnect#Login', which happens during the login section of the reconnect function
47+
}
48+
```
49+
50+
An example of implementation of metricizing the event would be:
51+
52+
```javascript
53+
agent.on('error', (error, context) => {
54+
metricsInterface.countFailure(context.location, 1);
55+
});
56+
```
57+
58+
## Reconnect General Failure Cases
59+
### Error codes 429 or 5xx
60+
61+
This indicates that you might be rate-limited or the service is down. Please implement a retry logic with exponential backoff on the [reconnect()](README.md#reconnectskiptokengeneration) function
62+
**without** token generation. You can copy the `_reconnect` function from the [closed event section](README.md#reconnect-with-retry). For example:
63+
64+
```javascript
65+
// on connected cancel any retry interval remaining from reconnect attempt
66+
agent.on('connected', () => {
67+
clearTimeout(agent._retryConnection);
68+
});
69+
70+
agent.on('error', (err, context) => {
71+
if (err && (err.code === 429 || err.code >= 500)) {
72+
agent._reconnect(true); // do not re-generate token
73+
}
74+
});
75+
```
76+
77+
### Error codes 401 or 403
78+
79+
This indicates that your token might be expired. Please implement a retry logic with exponential backoff on the [reconnect()](README.md#reconnectskiptokengeneration) function
80+
**with** token generation. You can copy the `_reconnect` function from the [closed event section](README.md#reconnect-with-retry). For example:
81+
82+
```javascript
83+
agent.on('error', (err, context) => {
84+
if (err && (err.code === 401 || err.code 403)) {
85+
agent._reconnect(); // regenerate token
86+
}
87+
});
88+
```
89+
90+
91+
## Details of the Context Location
92+
93+
### Connect#CSDS
94+
95+
#### Description
96+
97+
This happens when the bot is trying to contact to the LivePerson's domains service when the bot is trying to establish a WebSocket connection
98+
for the very first time.
99+
100+
It happens inside the [connect](README.md#connectcallback) function.
101+
102+
#### Failure Cases
103+
104+
Please refer to [General Failure Cases](#reconnect-general-failure-cases).
105+
106+
### Connect#Login
107+
108+
#### Description
109+
110+
This happens when the bot is trying to login to LivePerson when the bot is trying to establish a WebSocket connection
111+
for the very first time.
112+
113+
It happens inside the [connect](README.md#connectcallback) function.
114+
115+
#### Failure Cases
116+
117+
Please refer to [General Failure Cases](#reconnect-general-failure-cases).
118+
119+
### Reconnect#CSDS
120+
121+
#### Description
122+
123+
This happens when the bot is trying to contact to the LivePerson's domains service when the bot is trying to establish a WebSocket connection after it was disconnected.
124+
125+
It happens inside the [reconnect(skipTokenGeneration)](README.md#reconnectskiptokengeneration) function.
126+
127+
#### Failure Cases
128+
129+
Please refer to [General Failure Cases](#reconnect-general-failure-cases).
130+
131+
### Reconnect#Relogin#WS
132+
133+
#### Description
134+
135+
This happens when the bot is trying to login and re-establish a WS connection to LivePerson after the bot was disconnected.
136+
137+
It happens inside the [reconnect(skipTokenGeneration)](README.md#reconnectskiptokengeneration) function.
138+
139+
#### Failure Cases
140+
141+
Please refer to [General Failure Cases](#reconnect-general-failure-cases).
142+
143+
### RefreshSession#CSDS
144+
145+
This happens when the bot is trying to contact to the LivePerson's domains service when the bot is trying to prolong the agent's session.
146+
147+
It happens inside the [refreshSession(callback)](README.md#refreshsessioncallback) function.
148+
149+
#### Failure Cases
150+
151+
##### Error codes 429 or 5xx for Refresh Sessions
152+
153+
This indicates that you might be rate-limited or the service is down. Please implement a retry logic with exponential backoff on the [refreshSession(callback)](README.md#refreshsessioncallback) function.
154+
155+
If you want to attempt to reconnect repeatedly you should initiate a periodic reconnect attempt here. **LivePerson recommends that you make periodic reconnect attempts at increasing intervals up to a finite number of attempts in order to prevent flooding our service and being blocked as a potentially abusive client**. See [LivePerson's retry policy guidelines](https://developers.liveperson.com/guides-retry-policy.html) for more information.
156+
157+
In the sample below we attempt to reconnect 35 times, waiting 5 seconds the first time and increasing the interval by a factor of 1.25 between each attempt.
158+
159+
###### Reconnect with Retry
160+
161+
```javascript
162+
const reconnectInterval = 5; // in seconds
163+
const reconnectAttempts = 35;
164+
const reconnectRatio = 1.25; // ratio in the geometric series used to determine reconnect exponential back-off
165+
166+
agent._retryRefreshSession = (delay = reconnectInterval, attempt = 1) => {
167+
// Clear the timeouts from before
168+
clearTimeout(agent._refreshRetryConnection);
169+
170+
agent._refreshRetryConnection = setTimeout(() => {
171+
agent.refreshSession(() => {});
172+
if (++attempt <= reconnectAttempts) {
173+
agent._retryRefreshSession(delay * reconnectRatio, attempt);
174+
}
175+
}, delay * 1000);
176+
}
177+
```
178+
###### Retry Logic Example
179+
180+
```javascript
181+
// on success of the RefreshSession Events, we should cancel the retry timeout _refreshRetryConnection above
182+
// and restart the refreshSession loop to avoid it being stopped
183+
agent.on('success', (err, context) => {
184+
if (context.startsWith('RefreshSession')) {
185+
clearTimeout(agent._refreshRetryConnection);
186+
// Restart the refreshSession loop
187+
this.startPeriodicRefreshSession();
188+
}
189+
});
190+
191+
// 429 and 5xx cases
192+
agent.on('error', (err, context) => {
193+
if (err && (err.code === 429 || err.code >= 500) && context.location.startsWith('RefreshSession')) {
194+
agent._retryRefreshSession(); // The _retryRefreshSession function from above on the #Reconnect with Retry header
195+
}
196+
});
197+
```
198+
199+
### RefreshSession#REST
200+
201+
This happens when the bot is trying to contact to the API endpoint to prolong the agent's session.
202+
203+
It happens inside the [refreshSession(callback)](README.md#refreshsessioncallback) function.
204+
205+
#### Failure Cases
206+
207+
Please refer to the [Refresh Session's Failure Cases](#error-codes-429-or-5xx-for-refresh-sessions)
208+
209+
### RefreshSession#Relogin#WS
210+
211+
This happens when the bot is trying to contact to re-connect the agent bot when a bearer token is expired.
212+
213+
It happens inside the [refreshSession(callback)](README.md#refreshsessioncallback) function.
214+
215+
#### Failure Cases
216+
217+
Please refer to the [Refresh Session's Failure Cases](#error-codes-429-or-5xx-for-refresh-sessions)

0 commit comments

Comments
 (0)