diff --git a/src/lib/db/event-store.ts b/src/lib/db/event-store.ts index 6bd13fde56..aba36f18a0 100644 --- a/src/lib/db/event-store.ts +++ b/src/lib/db/event-store.ts @@ -164,6 +164,11 @@ class EventStore extends EventEmitter implements IEventStore { } } + async getLatestId(): Promise { + const item = await this.db(TABLE).max('id').first(); + return item.max; + } + rowToEvent(row: IEventTable): IEvent { return { id: row.id, diff --git a/src/lib/routes/client-api/feature.ts b/src/lib/routes/client-api/feature.ts index 664eed7dc9..36533613bb 100644 --- a/src/lib/routes/client-api/feature.ts +++ b/src/lib/routes/client-api/feature.ts @@ -11,6 +11,7 @@ import NotFoundError from '../../error/notfound-error'; import { IAuthRequest } from '../unleash-types'; import ApiUser from '../../types/api-user'; import { ALL } from '../../types/models/api-token'; +import EventService from '../../services/event-service'; const version = 2; @@ -24,19 +25,25 @@ export default class FeatureController extends Controller { private featureToggleServiceV2: FeatureToggleService; + private eventService: EventService; + private readonly cache: boolean; private cachedFeatures: any; + private latestEventId: number; + constructor( { featureToggleServiceV2, - }: Pick, + eventService, + }: Pick, config: IUnleashConfig, ) { super(config); const { experimental } = config; this.featureToggleServiceV2 = featureToggleServiceV2; + this.eventService = eventService; this.logger = config.getLogger('client-api/feature.js'); this.get('/', this.getAll); this.get('/:featureName', this.getFeatureToggle); @@ -56,6 +63,20 @@ export default class FeatureController extends Controller { }, ); } + if (this.cache) { + process.nextTick(async () => { + this.latestEventId = await this.eventService.getLatestId(); + setInterval(async () => { + const eventId = await this.eventService.getLatestId(); + console.log(eventId); + if (this.latestEventId !== eventId) { + console.log('clear cache'); + this.latestEventId = eventId; + await this.cachedFeatures.clear(); + } + }, 500); + }); + } } private async resolveQuery( diff --git a/src/lib/services/event-service.ts b/src/lib/services/event-service.ts index e31456f420..6429221fdb 100644 --- a/src/lib/services/event-service.ts +++ b/src/lib/services/event-service.ts @@ -28,6 +28,10 @@ export default class EventService { async getEventsForProject(project: string): Promise { return this.eventStore.getEventsFilterByProject(project); } + + async getLatestId(): Promise { + return this.eventStore.getLatestId(); + } } module.exports = EventService; diff --git a/src/lib/services/feature-toggle-service.ts b/src/lib/services/feature-toggle-service.ts index d237c87c62..a6afeb063d 100644 --- a/src/lib/services/feature-toggle-service.ts +++ b/src/lib/services/feature-toggle-service.ts @@ -420,6 +420,7 @@ class FeatureToggleService { async getClientFeatures( query?: IFeatureToggleQuery, ): Promise { + console.log('fetch!'); return this.featureToggleClientStore.getClient(query); } diff --git a/src/lib/types/stores/event-store.ts b/src/lib/types/stores/event-store.ts index 365cf89ae8..1fa258a56b 100644 --- a/src/lib/types/stores/event-store.ts +++ b/src/lib/types/stores/event-store.ts @@ -9,4 +9,5 @@ export interface IEventStore extends Store, EventEmitter { getEventsFilterByType(name: string): Promise; getEventsForFeature(featureName: string): Promise; getEventsFilterByProject(project: string): Promise; + getLatestId(): Promise; } diff --git a/src/server-dev.ts b/src/server-dev.ts index f408dfaec2..32487af813 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -32,6 +32,10 @@ process.nextTick(async () => { metricsV2: { enabled: true, }, + clientFeatureMemoize: { + enabled: true, + maxAge: 120_000, + }, }, authentication: { initApiTokens: [ diff --git a/src/test/fixtures/fake-event-store.ts b/src/test/fixtures/fake-event-store.ts index 8fb83b1243..7d0bddc580 100644 --- a/src/test/fixtures/fake-event-store.ts +++ b/src/test/fixtures/fake-event-store.ts @@ -11,6 +11,10 @@ class FakeEventStore extends EventEmitter implements IEventStore { this.events = []; } + getLatestId(): Promise { + return Promise.resolve(1); + } + async getEventsForFeature(featureName: string): Promise { return this.events.filter((e) => e.featureName === featureName); }