@@ -236,25 +236,35 @@ namespace ts.server {
236
236
return `${ d . getHours ( ) } :${ d . getMinutes ( ) } :${ d . getSeconds ( ) } .${ d . getMilliseconds ( ) } ` ;
237
237
}
238
238
239
+ interface QueuedOperation {
240
+ operationId : string ;
241
+ operation : ( ) => void ;
242
+ }
243
+
239
244
class NodeTypingsInstaller implements ITypingsInstaller {
240
245
private installer : NodeChildProcess ;
241
246
private installerPidReported = false ;
242
247
private socket : NodeSocket ;
243
248
private projectService : ProjectService ;
244
- private throttledOperations : ThrottledOperations ;
245
249
private eventSender : EventSender ;
250
+ private activeRequestCount = 0 ;
251
+ private requestQueue : QueuedOperation [ ] = [ ] ;
252
+ private requestMap = createMap < QueuedOperation > ( ) ; // Maps operation ID to newest requestQueue entry with that ID
253
+
254
+ private static readonly maxActiveRequestCount = 10 ;
255
+ private static readonly requestDelayMillis = 100 ;
256
+
246
257
247
258
constructor (
248
259
private readonly telemetryEnabled : boolean ,
249
260
private readonly logger : server . Logger ,
250
- host : ServerHost ,
261
+ private readonly host : ServerHost ,
251
262
eventPort : number ,
252
263
readonly globalTypingsCacheLocation : string ,
253
264
readonly typingSafeListLocation : string ,
254
265
readonly typesMapLocation : string ,
255
266
private readonly npmLocation : string | undefined ,
256
267
private newLine : string ) {
257
- this . throttledOperations = new ThrottledOperations ( host ) ;
258
268
if ( eventPort ) {
259
269
const s = net . connect ( { port : eventPort } , ( ) => {
260
270
this . socket = s ;
@@ -338,12 +348,26 @@ namespace ts.server {
338
348
this . logger . info ( `Scheduling throttled operation: ${ JSON . stringify ( request ) } ` ) ;
339
349
}
340
350
}
341
- this . throttledOperations . schedule ( project . getProjectName ( ) , /*ms*/ 250 , ( ) => {
351
+
352
+ const operationId = project . getProjectName ( ) ;
353
+ const operation = ( ) => {
342
354
if ( this . logger . hasLevel ( LogLevel . verbose ) ) {
343
355
this . logger . info ( `Sending request: ${ JSON . stringify ( request ) } ` ) ;
344
356
}
345
357
this . installer . send ( request ) ;
346
- } ) ;
358
+ } ;
359
+ const queuedRequest : QueuedOperation = { operationId, operation } ;
360
+
361
+ if ( this . activeRequestCount < NodeTypingsInstaller . maxActiveRequestCount ) {
362
+ this . scheduleRequest ( queuedRequest ) ;
363
+ }
364
+ else {
365
+ if ( this . logger . hasLevel ( LogLevel . verbose ) ) {
366
+ this . logger . info ( `Deferring request for: ${ operationId } ` ) ;
367
+ }
368
+ this . requestQueue . push ( queuedRequest ) ;
369
+ this . requestMap . set ( operationId , queuedRequest ) ;
370
+ }
347
371
}
348
372
349
373
private handleMessage ( response : SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse ) {
@@ -404,11 +428,39 @@ namespace ts.server {
404
428
return ;
405
429
}
406
430
431
+ if ( this . activeRequestCount > 0 ) {
432
+ this . activeRequestCount -- ;
433
+ }
434
+ else {
435
+ Debug . fail ( "Received too many responses" ) ;
436
+ }
437
+
438
+ while ( this . requestQueue . length > 0 ) {
439
+ const queuedRequest = this . requestQueue . shift ( ) ;
440
+ if ( this . requestMap . get ( queuedRequest . operationId ) == queuedRequest ) {
441
+ this . requestMap . delete ( queuedRequest . operationId ) ;
442
+ this . scheduleRequest ( queuedRequest ) ;
443
+ break ;
444
+ }
445
+
446
+ if ( this . logger . hasLevel ( LogLevel . verbose ) ) {
447
+ this . logger . info ( `Skipping defunct request for: ${ queuedRequest . operationId } ` ) ;
448
+ }
449
+ }
450
+
407
451
this . projectService . updateTypingsForProject ( response ) ;
408
452
if ( response . kind === ActionSet && this . socket ) {
409
453
this . sendEvent ( 0 , "setTypings" , response ) ;
410
454
}
411
455
}
456
+
457
+ private scheduleRequest ( request : QueuedOperation ) {
458
+ if ( this . logger . hasLevel ( LogLevel . verbose ) ) {
459
+ this . logger . info ( `Scheduling request for: ${ request . operationId } ` ) ;
460
+ }
461
+ this . activeRequestCount ++ ;
462
+ this . host . setTimeout ( request . operation , NodeTypingsInstaller . requestDelayMillis ) ;
463
+ }
412
464
}
413
465
414
466
class IOSession extends Session {
0 commit comments