@@ -9,6 +9,8 @@ import { BaseWatcher } from '../baseWatcher.js';
9
9
import { isLinux } from '../../../../../base/common/platform.js' ;
10
10
import { INonRecursiveWatchRequest , INonRecursiveWatcher , IRecursiveWatcherWithSubscribe } from '../../../common/watcher.js' ;
11
11
import { NodeJSFileWatcherLibrary } from './nodejsWatcherLib.js' ;
12
+ import { ThrottledWorker } from '../../../../../base/common/async.js' ;
13
+ import { MutableDisposable } from '../../../../../base/common/lifecycle.js' ;
12
14
13
15
export interface INodeJSWatcherInstance {
14
16
@@ -30,6 +32,8 @@ export class NodeJSWatcher extends BaseWatcher implements INonRecursiveWatcher {
30
32
private readonly _watchers = new Map < string /* path */ | number /* correlation ID */ , INodeJSWatcherInstance > ( ) ;
31
33
get watchers ( ) { return this . _watchers . values ( ) ; }
32
34
35
+ private readonly worker = this . _register ( new MutableDisposable < ThrottledWorker < INonRecursiveWatchRequest > > ( ) ) ;
36
+
33
37
constructor ( protected readonly recursiveWatcher : IRecursiveWatcherWithSubscribe | undefined ) {
34
38
super ( ) ;
35
39
}
@@ -61,15 +65,36 @@ export class NodeJSWatcher extends BaseWatcher implements INonRecursiveWatcher {
61
65
this . trace ( `Request to stop watching: ${ Array . from ( watchersToStop ) . map ( watcher => this . requestToString ( watcher . request ) ) . join ( ',' ) } ` ) ;
62
66
}
63
67
68
+ // Stop the worker
69
+ this . worker . clear ( ) ;
70
+
64
71
// Stop watching as instructed
65
72
for ( const watcher of watchersToStop ) {
66
73
this . stopWatching ( watcher ) ;
67
74
}
68
75
69
76
// Start watching as instructed
70
- for ( const request of requestsToStart ) {
71
- this . startWatching ( request ) ;
72
- }
77
+ this . createWatchWorker ( ) . work ( requestsToStart ) ;
78
+ }
79
+
80
+ private createWatchWorker ( ) : ThrottledWorker < INonRecursiveWatchRequest > {
81
+
82
+ // We see very large amount of non-recursive file watcher requests
83
+ // in large workspaces. To prevent the overhead of starting thousands
84
+ // of watchers at once, we use a throttled worker to distribute this
85
+ // work over time.
86
+
87
+ this . worker . value = new ThrottledWorker < INonRecursiveWatchRequest > ( {
88
+ maxWorkChunkSize : 100 , // only start 100 watchers at once before...
89
+ throttleDelay : 100 , // ...resting for 100ms until we start watchers again...
90
+ maxBufferedWork : Number . MAX_VALUE // ...and never refuse any work.
91
+ } , requests => {
92
+ for ( const request of requests ) {
93
+ this . startWatching ( request ) ;
94
+ }
95
+ } ) ;
96
+
97
+ return this . worker . value ;
73
98
}
74
99
75
100
private requestToWatcherKey ( request : INonRecursiveWatchRequest ) : string | number {
0 commit comments