File tree Expand file tree Collapse file tree 5 files changed +59
-4
lines changed
__tests__/internal/events Expand file tree Collapse file tree 5 files changed +59
-4
lines changed Original file line number Diff line number Diff line change @@ -658,7 +658,9 @@ describe('given an event processor', () => {
658
658
await expect ( eventProcessor . flush ( ) ) . rejects . toThrow ( 'some error' ) ;
659
659
660
660
eventProcessor . sendEvent ( new InputIdentifyEvent ( Context . fromLDContext ( user ) ) ) ;
661
- await expect ( eventProcessor . flush ( ) ) . rejects . toThrow ( / S D K k e y i s i n v a l i d / ) ;
661
+ await expect ( eventProcessor . flush ( ) ) . rejects . toThrow (
662
+ 'Events cannot be posted because a permanent error has been encountered.' ,
663
+ ) ;
662
664
} ) ;
663
665
664
666
it ( 'swallows errors from failed background flush' , async ( ) => {
Original file line number Diff line number Diff line change @@ -43,9 +43,29 @@ export class LDClientError extends Error {
43
43
}
44
44
}
45
45
46
+ /**
47
+ * Check if the HTTP error is recoverable. This will return false if a request
48
+ * made with any payload could not recover. If the reason for the failure
49
+ * is payload specific, for instance a payload that is too large, then
50
+ * it could recover with a different payload.
51
+ */
46
52
export function isHttpRecoverable ( status : number ) {
47
53
if ( status >= 400 && status < 500 ) {
48
54
return status === 400 || status === 408 || status === 429 ;
49
55
}
50
56
return true ;
51
57
}
58
+
59
+ /**
60
+ * Returns true if the status could recover for a different payload.
61
+ *
62
+ * When used with event processing this indicates that we should discard
63
+ * the payload, but that a subsequent payload may succeed. Therefore we should
64
+ * not stop event processing.
65
+ */
66
+ export function isHttpLocallyRecoverable ( status : number ) {
67
+ if ( status === 413 ) {
68
+ return true ;
69
+ }
70
+ return isHttpRecoverable ( status ) ;
71
+ }
Original file line number Diff line number Diff line change @@ -168,7 +168,11 @@ export default class EventProcessor implements LDEventProcessor {
168
168
169
169
async flush ( ) : Promise < void > {
170
170
if ( this . shutdown ) {
171
- throw new LDInvalidSDKKeyError ( 'Events cannot be posted because SDK key is invalid' ) ;
171
+ throw new LDInvalidSDKKeyError (
172
+ 'Events cannot be posted because a permanent error has been encountered. ' +
173
+ 'This is most likely an invalid SDK key. The specific error information ' +
174
+ 'is logged independently.' ,
175
+ ) ;
172
176
}
173
177
174
178
const eventsToFlush = this . queue ;
Original file line number Diff line number Diff line change @@ -196,6 +196,23 @@ describe('given an event sender', () => {
196
196
} ) ;
197
197
} ) ;
198
198
199
+ it ( 'given a result for too large of a payload' , async ( ) => {
200
+ setupMockFetch ( 413 ) ;
201
+ eventSenderResult = await eventSender . sendEventData (
202
+ LDEventType . AnalyticsEvents ,
203
+ testEventData1 ,
204
+ ) ;
205
+
206
+ const errorMessage = `Received error 413 for event posting - giving up permanently` ;
207
+
208
+ const { status, error } = eventSenderResult ;
209
+
210
+ expect ( mockFetch ) . toHaveBeenCalledTimes ( 1 ) ;
211
+ expect ( status ) . toEqual ( LDDeliveryStatus . Failed ) ;
212
+ expect ( error . name ) . toEqual ( 'LaunchDarklyUnexpectedResponseError' ) ;
213
+ expect ( error . message ) . toEqual ( errorMessage ) ;
214
+ } ) ;
215
+
199
216
describe . each ( [ 401 , 403 ] ) ( 'given unrecoverable errors' , ( responseStatusCode ) => {
200
217
beforeEach ( async ( ) => {
201
218
setupMockFetch ( responseStatusCode ) ;
Original file line number Diff line number Diff line change @@ -5,7 +5,11 @@ import {
5
5
LDEventSenderResult ,
6
6
LDEventType ,
7
7
} from '../../api/subsystem' ;
8
- import { isHttpRecoverable , LDUnexpectedResponseError } from '../../errors' ;
8
+ import {
9
+ isHttpLocallyRecoverable ,
10
+ isHttpRecoverable ,
11
+ LDUnexpectedResponseError ,
12
+ } from '../../errors' ;
9
13
import { ClientContext } from '../../options' ;
10
14
import { defaultHeaders , httpErrorMessage , sleep } from '../../utils' ;
11
15
@@ -80,7 +84,15 @@ export default class EventSender implements LDEventSender {
80
84
) ;
81
85
82
86
if ( ! isHttpRecoverable ( status ) ) {
83
- tryRes . status = LDDeliveryStatus . FailedAndMustShutDown ;
87
+ // If the HTTP request isn't recoverable. Meaning if we made the same request it
88
+ // would not recover, then we check if a different request could recover.
89
+ // If a different request could not recover, then we shutdown. If a different request could
90
+ // recover, then we just don't retry this specific request.
91
+ if ( ! isHttpLocallyRecoverable ( status ) ) {
92
+ tryRes . status = LDDeliveryStatus . FailedAndMustShutDown ;
93
+ } else {
94
+ tryRes . status = LDDeliveryStatus . Failed ;
95
+ }
84
96
tryRes . error = error ;
85
97
return tryRes ;
86
98
}
You can’t perform that action at this time.
0 commit comments