Skip to content

Commit 5dacf91

Browse files
committed
feat: disable polling by default and add visibility-based flag refresh
- Change DEFAULT_POLL_INTERVAL from 30000ms to 0 (polling disabled by default) - Add visibility change detection to re-fetch flags when page/app becomes visible - Add _visibilityChangeHandler property and _onVisibilityChange() method - Register/unregister visibility change listener in initialize/onClose - Re-fetches respect Retry-After rate limit headers - Emits ConfigurationChanged or Stale events based on fetch results
1 parent 3650a7f commit 5dacf91

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

libs/providers/ofrep-web/src/lib/ofrep-web-provider.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import type { FlagCache, MetadataCache } from './model/in-memory-cache';
3636
import type { OFREPWebProviderOptions } from './model/ofrep-web-provider-options';
3737

3838
export class OFREPWebProvider implements Provider {
39-
DEFAULT_POLL_INTERVAL = 30000;
39+
DEFAULT_POLL_INTERVAL = 0;
4040

4141
readonly metadata = {
4242
name: 'OpenFeature Remote Evaluation Protocol Web Provider',
@@ -57,6 +57,7 @@ export class OFREPWebProvider implements Provider {
5757
private _flagSetMetadataCache?: MetadataCache;
5858
private _context: EvaluationContext | undefined;
5959
private _pollingIntervalId?: number;
60+
private _visibilityChangeHandler = this._onVisibilityChange.bind(this);
6061

6162
constructor(options: OFREPWebProviderOptions, logger?: Logger) {
6263
this._options = options;
@@ -86,6 +87,11 @@ export class OFREPWebProvider implements Provider {
8687
this.startPolling();
8788
}
8889

90+
// Listen for page/app visibility changes to refetch flags when becoming visible
91+
if (typeof document !== 'undefined') {
92+
document.addEventListener('visibilitychange', this._visibilityChangeHandler);
93+
}
94+
8995
this._logger?.debug(`${this.metadata.name} initialized successfully`);
9096
} catch (error) {
9197
if (error instanceof OFREPApiUnauthorizedError || error instanceof OFREPForbiddenError) {
@@ -166,6 +172,9 @@ export class OFREPWebProvider implements Provider {
166172
*/
167173
onClose?(): Promise<void> {
168174
this.stopPolling();
175+
if (typeof document !== 'undefined') {
176+
document.removeEventListener('visibilitychange', this._visibilityChangeHandler);
177+
}
169178
this._ofrepAPI.close();
170179
return Promise.resolve();
171180
}
@@ -319,4 +328,30 @@ export class OFREPWebProvider implements Provider {
319328
clearInterval(this._pollingIntervalId);
320329
}
321330
}
331+
332+
/**
333+
* Handler for visibility changes (page/app becoming visible)
334+
* Re-fetches flags when the document becomes visible
335+
* @private
336+
*/
337+
private async _onVisibilityChange() {
338+
// Only re-fetch when the page becomes visible, not when it's hidden
339+
if (typeof document !== 'undefined' && document.visibilityState === 'visible') {
340+
try {
341+
const now = new Date();
342+
if (this._retryPollingAfter !== undefined && this._retryPollingAfter > now) {
343+
return;
344+
}
345+
const res = await this._fetchFlags(this._context);
346+
if (res.status === BulkEvaluationStatus.SUCCESS_WITH_CHANGES) {
347+
this.events?.emit(ClientProviderEvents.ConfigurationChanged, {
348+
message: 'Flags updated after visibility change',
349+
flagsChanged: res.flags,
350+
});
351+
}
352+
} catch (error) {
353+
this.events?.emit(ClientProviderEvents.Stale, { message: `Error while fetching after visibility change: ${error}` });
354+
}
355+
}
356+
}
322357
}

0 commit comments

Comments
 (0)