@@ -64,120 +64,9 @@ describe('Integration | rate-limiting behaviour', () => {
64
64
replay && replay . stop ( ) ;
65
65
} ) ;
66
66
67
- it . each ( [
68
- {
69
- statusCode : 429 ,
70
- headers : {
71
- 'x-sentry-rate-limits' : '30' ,
72
- 'retry-after' : null ,
73
- } ,
74
- } ,
75
- {
76
- statusCode : 429 ,
77
- headers : {
78
- 'x-sentry-rate-limits' : '30:replay' ,
79
- 'retry-after' : null ,
80
- } ,
81
- } ,
82
- {
83
- statusCode : 429 ,
84
- headers : {
85
- 'x-sentry-rate-limits' : null ,
86
- 'retry-after' : '30' ,
87
- } ,
88
- } ,
89
- ] as TransportMakeRequestResponse [ ] ) (
90
- 'pauses recording and flushing a rate limit is hit and resumes both after the rate limit duration is over %j' ,
91
- async rateLimitResponse => {
92
- expect ( replay . session ?. segmentId ) . toBe ( 0 ) ;
93
- jest . spyOn ( replay , 'pause' ) ;
94
- jest . spyOn ( replay , 'resume' ) ;
95
- // @ts -ignore private API
96
- jest . spyOn ( replay , '_handleRateLimit' ) ;
97
-
98
- const TEST_EVENT = { data : { } , timestamp : BASE_TIMESTAMP , type : 2 } ;
99
-
100
- mockTransportSend . mockImplementationOnce ( ( ) => {
101
- return Promise . resolve ( rateLimitResponse ) ;
102
- } ) ;
103
-
104
- mockRecord . _emitter ( TEST_EVENT ) ;
105
-
106
- // T = base + 5
107
- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
108
-
109
- expect ( mockRecord . takeFullSnapshot ) . not . toHaveBeenCalled ( ) ;
110
- expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
111
- expect ( replay ) . toHaveLastSentReplay ( { recordingData : JSON . stringify ( [ TEST_EVENT ] ) } ) ;
112
-
113
- expect ( replay [ '_handleRateLimit' ] ) . toHaveBeenCalledTimes ( 1 ) ;
114
- // resume() was called once before we even started
115
- expect ( replay . resume ) . not . toHaveBeenCalled ( ) ;
116
- expect ( replay . pause ) . toHaveBeenCalledTimes ( 1 ) ;
117
-
118
- // No user activity to trigger an update
119
- expect ( replay . session ?. lastActivity ) . toBe ( BASE_TIMESTAMP ) ;
120
- expect ( replay . session ?. segmentId ) . toBe ( 1 ) ;
121
-
122
- // let's simulate the rate-limit time of inactivity (30secs) and check that we don't do anything in the meantime
123
- const TEST_EVENT2 = { data : { } , timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY , type : 3 } ;
124
- for ( let i = 0 ; i < 5 ; i ++ ) {
125
- const ev = {
126
- ...TEST_EVENT2 ,
127
- timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY * ( i + 1 ) ,
128
- } ;
129
- mockRecord . _emitter ( ev ) ;
130
- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
131
- expect ( replay . isPaused ( ) ) . toBe ( true ) ;
132
- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 1 ) ;
133
- expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
134
- }
135
-
136
- // T = base + 35
137
- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
138
-
139
- // now, recording should resume and first, we expect a checkout event to be sent, as resume()
140
- // should trigger a full snapshot
141
- expect ( replay . resume ) . toHaveBeenCalledTimes ( 1 ) ;
142
- expect ( replay . isPaused ( ) ) . toBe ( false ) ;
143
-
144
- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 2 ) ;
145
- expect ( replay ) . toHaveLastSentReplay ( {
146
- recordingData : JSON . stringify ( [
147
- { data : { isCheckout : true } , timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY * 7 , type : 2 } ,
148
- ] ) ,
149
- } ) ;
150
-
151
- // and let's also emit a new event and check that it is recorded
152
- const TEST_EVENT3 = {
153
- data : { } ,
154
- timestamp : BASE_TIMESTAMP + 7 * DEFAULT_FLUSH_MIN_DELAY ,
155
- type : 3 ,
156
- } ;
157
- mockRecord . _emitter ( TEST_EVENT3 ) ;
158
-
159
- // T = base + 40
160
- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
161
- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 3 ) ;
162
- expect ( replay ) . toHaveLastSentReplay ( { recordingData : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
163
-
164
- // nothing should happen afterwards
165
- // T = base + 60
166
- await advanceTimers ( 20_000 ) ;
167
- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 3 ) ;
168
- expect ( replay ) . toHaveLastSentReplay ( { recordingData : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
169
-
170
- // events array should be empty
171
- expect ( replay . eventBuffer ?. hasEvents ) . toBe ( false ) ;
172
- } ,
173
- ) ;
174
-
175
- it ( 'handles rate-limits from a plain 429 response without any retry time' , async ( ) => {
67
+ it ( 'handles rate-limit 429 responses by stopping the replay' , async ( ) => {
176
68
expect ( replay . session ?. segmentId ) . toBe ( 0 ) ;
177
- jest . spyOn ( replay , 'pause' ) ;
178
- jest . spyOn ( replay , 'resume' ) ;
179
- // @ts -ignore private API
180
- jest . spyOn ( replay , '_handleRateLimit' ) ;
69
+ jest . spyOn ( replay , 'stop' ) ;
181
70
182
71
const TEST_EVENT = { data : { } , timestamp : BASE_TIMESTAMP , type : 2 } ;
183
72
@@ -194,99 +83,33 @@ describe('Integration | rate-limiting behaviour', () => {
194
83
expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
195
84
expect ( replay ) . toHaveLastSentReplay ( { recordingData : JSON . stringify ( [ TEST_EVENT ] ) } ) ;
196
85
197
- expect ( replay [ '_handleRateLimit' ] ) . toHaveBeenCalledTimes ( 1 ) ;
198
- // resume() was called once before we even started
199
- expect ( replay . resume ) . not . toHaveBeenCalled ( ) ;
200
- expect ( replay . pause ) . toHaveBeenCalledTimes ( 1 ) ;
86
+ expect ( replay . stop ) . toHaveBeenCalledTimes ( 1 ) ;
201
87
202
88
// No user activity to trigger an update
203
89
expect ( replay . session ?. lastActivity ) . toBe ( BASE_TIMESTAMP ) ;
204
90
expect ( replay . session ?. segmentId ) . toBe ( 1 ) ;
205
91
206
- // let's simulate the rate-limit time of inactivity (60secs) and check that we don't do anything in the meantime
92
+ // let's simulate the default rate-limit time of inactivity (60secs) and check that we
93
+ // don't do anything in the meantime or after the time has passed
207
94
// 60secs are the default we fall back to in the plain 429 case in updateRateLimits()
208
- const TEST_EVENT2 = { data : { } , timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY , type : 3 } ;
209
- for ( let i = 0 ; i < 11 ; i ++ ) {
210
- const ev = {
211
- ...TEST_EVENT2 ,
212
- timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY * ( i + 1 ) ,
213
- } ;
214
- mockRecord . _emitter ( ev ) ;
215
- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
216
- expect ( replay . isPaused ( ) ) . toBe ( true ) ;
217
- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 1 ) ;
218
- expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
219
- }
220
95
221
96
// T = base + 60
222
- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
223
-
224
- // now, recording should resume and first, we expect a checkout event to be sent, as resume()
225
- // should trigger a full snapshot
226
- expect ( replay . resume ) . toHaveBeenCalledTimes ( 1 ) ;
227
- expect ( replay . isPaused ( ) ) . toBe ( false ) ;
97
+ await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY * 12 ) ;
228
98
229
- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 2 ) ;
230
- expect ( replay ) . toHaveLastSentReplay ( {
231
- recordingData : JSON . stringify ( [
232
- { data : { isCheckout : true } , timestamp : BASE_TIMESTAMP + DEFAULT_FLUSH_MIN_DELAY * 13 , type : 2 } ,
233
- ] ) ,
234
- } ) ;
99
+ expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 1 ) ;
100
+ expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
235
101
236
- // and let's also emit a new event and check that it is recorded
102
+ // and let's also emit a new event and check that it is not recorded
237
103
const TEST_EVENT3 = {
238
104
data : { } ,
239
105
timestamp : BASE_TIMESTAMP + 7 * DEFAULT_FLUSH_MIN_DELAY ,
240
106
type : 3 ,
241
107
} ;
242
108
mockRecord . _emitter ( TEST_EVENT3 ) ;
243
109
244
- // T = base + 65
245
- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
246
- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 3 ) ;
247
- expect ( replay ) . toHaveLastSentReplay ( { recordingData : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
248
-
249
- // nothing should happen afterwards
250
- // T = base + 85
110
+ // T = base + 80
251
111
await advanceTimers ( 20_000 ) ;
252
- expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 3 ) ;
253
- expect ( replay ) . toHaveLastSentReplay ( { recordingData : JSON . stringify ( [ TEST_EVENT3 ] ) } ) ;
254
-
255
- // events array should be empty
256
- expect ( replay . eventBuffer ?. hasEvents ) . toBe ( false ) ;
257
- } ) ;
258
-
259
- it ( "doesn't do anything, if a rate limit is hit and recording is already paused" , async ( ) => {
260
- let paused = false ;
261
- expect ( replay . session ?. segmentId ) . toBe ( 0 ) ;
262
- jest . spyOn ( replay , 'isPaused' ) . mockImplementation ( ( ) => {
263
- return paused ;
264
- } ) ;
265
- jest . spyOn ( replay , 'pause' ) ;
266
- jest . spyOn ( replay , 'resume' ) ;
267
- // @ts -ignore private API
268
- jest . spyOn ( replay , '_handleRateLimit' ) ;
269
-
270
- const TEST_EVENT = { data : { } , timestamp : BASE_TIMESTAMP , type : 2 } ;
271
-
272
- mockTransportSend . mockImplementationOnce ( ( ) => {
273
- return Promise . resolve ( { statusCode : 429 } ) ;
274
- } ) ;
275
-
276
- mockRecord . _emitter ( TEST_EVENT ) ;
277
- paused = true ;
278
-
279
- // T = base + 5
280
- await advanceTimers ( DEFAULT_FLUSH_MIN_DELAY ) ;
281
-
282
- expect ( mockRecord . takeFullSnapshot ) . not . toHaveBeenCalled ( ) ;
112
+ expect ( mockSendReplayRequest ) . toHaveBeenCalledTimes ( 1 ) ;
283
113
expect ( mockTransportSend ) . toHaveBeenCalledTimes ( 1 ) ;
284
-
285
- expect ( replay ) . toHaveLastSentReplay ( { recordingData : JSON . stringify ( [ TEST_EVENT ] ) } ) ;
286
-
287
- expect ( replay [ '_handleRateLimit' ] ) . toHaveBeenCalledTimes ( 1 ) ;
288
- expect ( replay . resume ) . not . toHaveBeenCalled ( ) ;
289
- expect ( replay . isPaused ) . toHaveBeenCalledTimes ( 2 ) ;
290
- expect ( replay . pause ) . not . toHaveBeenCalled ( ) ;
291
114
} ) ;
292
115
} ) ;
0 commit comments