@@ -8,18 +8,28 @@ import { Logger } from "./logging";
88 * same time.
99 */
1010export abstract class Discovery < T > extends DisposableObject {
11- private retry = false ;
12- private discoveryInProgress = false ;
11+ private restartWhenFinished = false ;
12+ private currentDiscoveryPromise : Promise < void > | undefined ;
1313
1414 constructor ( private readonly name : string , private readonly logger : Logger ) {
1515 super ( ) ;
1616 }
1717
18+ /**
19+ * Returns the promise of the currently running refresh operation, if one is in progress.
20+ * Otherwise returns a promise that resolves immediately.
21+ */
22+ public waitForCurrentRefresh ( ) : Promise < void > {
23+ return this . currentDiscoveryPromise ?? Promise . resolve ( ) ;
24+ }
25+
1826 /**
1927 * Force the discovery process to run. Normally invoked by the derived class when a relevant file
2028 * system change is detected.
29+ *
30+ * Returns a promise that resolves when the refresh is complete, including any retries.
2131 */
22- public refresh ( ) : void {
32+ public refresh ( ) : Promise < void > {
2333 // We avoid having multiple discovery operations in progress at the same time. Otherwise, if we
2434 // got a storm of refresh requests due to, say, the copying or deletion of a large directory
2535 // tree, we could potentially spawn a separate simultaneous discovery operation for each
@@ -36,49 +46,48 @@ export abstract class Discovery<T> extends DisposableObject {
3646 // other change notifications that might be coming along. However, this would create more
3747 // latency in the common case, in order to save a bit of latency in the uncommon case.
3848
39- if ( this . discoveryInProgress ) {
49+ if ( this . currentDiscoveryPromise !== undefined ) {
4050 // There's already a discovery operation in progress. Tell it to restart when it's done.
41- this . retry = true ;
51+ this . restartWhenFinished = true ;
4252 } else {
4353 // No discovery in progress, so start one now.
44- this . discoveryInProgress = true ;
45- this . launchDiscovery ( ) ;
54+ this . currentDiscoveryPromise = this . launchDiscovery ( ) . finally ( ( ) => {
55+ this . currentDiscoveryPromise = undefined ;
56+ } ) ;
4657 }
58+ return this . currentDiscoveryPromise ;
4759 }
4860
4961 /**
5062 * Starts the asynchronous discovery operation by invoking the `discover` function. When the
5163 * discovery operation completes, the `update` function will be invoked with the results of the
5264 * discovery.
5365 */
54- private launchDiscovery ( ) : void {
55- const discoveryPromise = this . discover ( ) ;
56- discoveryPromise
57- . then ( ( results ) => {
58- if ( ! this . retry ) {
59- // Update any listeners with the results of the discovery.
60- this . discoveryInProgress = false ;
61- this . update ( results ) ;
62- }
63- } )
64-
65- . catch ( ( err : unknown ) => {
66- void this . logger . log (
67- `${ this . name } failed. Reason: ${ getErrorMessage ( err ) } ` ,
68- ) ;
69- } )
66+ private async launchDiscovery ( ) : Promise < void > {
67+ let results : T | undefined ;
68+ try {
69+ results = await this . discover ( ) ;
70+ } catch ( err ) {
71+ void this . logger . log (
72+ `${ this . name } failed. Reason: ${ getErrorMessage ( err ) } ` ,
73+ ) ;
74+ results = undefined ;
75+ }
7076
71- . finally ( ( ) => {
72- if ( this . retry ) {
73- // Another refresh request came in while we were still running a previous discovery
74- // operation. Since the discovery results we just computed are now stale, we'll launch
75- // another discovery operation instead of updating.
76- // Note that by doing this inside of `finally`, we will relaunch discovery even if the
77- // initial discovery operation failed.
78- this . retry = false ;
79- this . launchDiscovery ( ) ;
80- }
81- } ) ;
77+ if ( this . restartWhenFinished ) {
78+ // Another refresh request came in while we were still running a previous discovery
79+ // operation. Since the discovery results we just computed are now stale, we'll launch
80+ // another discovery operation instead of updating.
81+ // We want to relaunch discovery regardless of if the initial discovery operation
82+ // succeeded or failed.
83+ this . restartWhenFinished = false ;
84+ await this . launchDiscovery ( ) ;
85+ } else {
86+ // If the discovery was successful, then update any listeners with the results.
87+ if ( results !== undefined ) {
88+ this . update ( results ) ;
89+ }
90+ }
8291 }
8392
8493 /**
0 commit comments