diff --git a/src/lib/features/client-feature-toggles/client-feature-toggle-service.ts b/src/lib/features/client-feature-toggles/client-feature-toggle-service.ts index f80f2341cf..a0d85e042e 100644 --- a/src/lib/features/client-feature-toggles/client-feature-toggle-service.ts +++ b/src/lib/features/client-feature-toggles/client-feature-toggle-service.ts @@ -10,9 +10,9 @@ import type { Logger } from '../../logger'; import type { FeatureConfigurationClient } from '../feature-toggle/types/feature-toggle-strategies-store-type'; import type { - RevisionCacheEntry, - ClientFeatureToggleCache, -} from './cache/client-feature-toggle-cache'; + RevisionDeltaEntry, + ClientFeatureToggleDelta, +} from './delta/client-feature-toggle-delta'; export class ClientFeatureToggleService { private logger: Logger; @@ -21,19 +21,19 @@ export class ClientFeatureToggleService { private segmentReadModel: ISegmentReadModel; - private clientFeatureToggleCache: ClientFeatureToggleCache | null = null; + private clientFeatureToggleDelta: ClientFeatureToggleDelta | null = null; constructor( { clientFeatureToggleStore, }: Pick, segmentReadModel: ISegmentReadModel, - clientFeatureToggleCache: ClientFeatureToggleCache | null, + clientFeatureToggleCache: ClientFeatureToggleDelta | null, { getLogger }: Pick, ) { this.logger = getLogger('services/client-feature-toggle-service.ts'); this.segmentReadModel = segmentReadModel; - this.clientFeatureToggleCache = clientFeatureToggleCache; + this.clientFeatureToggleDelta = clientFeatureToggleCache; this.clientFeatureToggleStore = clientFeatureToggleStore; } @@ -44,9 +44,9 @@ export class ClientFeatureToggleService { async getClientDelta( revisionId: number | undefined, query: IFeatureToggleQuery, - ): Promise { - if (this.clientFeatureToggleCache !== null) { - return this.clientFeatureToggleCache.getDelta(revisionId, query); + ): Promise { + if (this.clientFeatureToggleDelta !== null) { + return this.clientFeatureToggleDelta.getDelta(revisionId, query); } else { throw new Error( 'Calling the partial updates but the cache is not initialized', diff --git a/src/lib/features/client-feature-toggles/createClientFeatureToggleService.ts b/src/lib/features/client-feature-toggles/createClientFeatureToggleService.ts index 3a7f454234..f48d98e0d1 100644 --- a/src/lib/features/client-feature-toggles/createClientFeatureToggleService.ts +++ b/src/lib/features/client-feature-toggles/createClientFeatureToggleService.ts @@ -5,7 +5,7 @@ import FakeClientFeatureToggleStore from './fakes/fake-client-feature-toggle-sto import { ClientFeatureToggleService } from './client-feature-toggle-service'; import { SegmentReadModel } from '../segment/segment-read-model'; import { FakeSegmentReadModel } from '../segment/fake-segment-read-model'; -import { createClientFeatureToggleCache } from './cache/createClientFeatureToggleCache'; +import { createClientFeatureToggleDelta } from './delta/createClientFeatureToggleDelta'; export const createClientFeatureToggleService = ( db: Db, @@ -22,7 +22,7 @@ export const createClientFeatureToggleService = ( const segmentReadModel = new SegmentReadModel(db); - const clientFeatureToggleCache = createClientFeatureToggleCache(db, config); + const clientFeatureToggleCache = createClientFeatureToggleDelta(db, config); const clientFeatureToggleService = new ClientFeatureToggleService( { diff --git a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-controller.ts b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-controller.ts similarity index 98% rename from src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-controller.ts rename to src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-controller.ts index 82c5a745fc..0d42aa7468 100644 --- a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-controller.ts +++ b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-controller.ts @@ -17,7 +17,7 @@ import type { OpenApiService } from '../../../services/openapi-service'; import { NONE } from '../../../types/permissions'; import { createResponseSchema } from '../../../openapi/util/create-response-schema'; import type { ClientFeatureToggleService } from '../client-feature-toggle-service'; -import type { RevisionCacheEntry } from './client-feature-toggle-cache'; +import type { RevisionDeltaEntry } from './client-feature-toggle-delta'; import { clientFeaturesDeltaSchema } from '../../../openapi'; import type { QueryOverride } from '../client-feature-toggle.controller'; @@ -142,7 +142,7 @@ export default class ClientFeatureToggleDeltaController extends Controller { async getDelta( req: IAuthRequest, - res: Response, + res: Response, ): Promise { if (!this.flagResolver.isEnabled('deltaApi')) { throw new NotFoundError(); diff --git a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-read-model-type.ts b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-read-model-type.ts similarity index 68% rename from src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-read-model-type.ts rename to src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-read-model-type.ts index ed9f0e6e04..3b82bd508f 100644 --- a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-read-model-type.ts +++ b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-read-model-type.ts @@ -1,14 +1,14 @@ import type { IFeatureToggleQuery } from '../../../types'; import type { FeatureConfigurationClient } from '../../feature-toggle/types/feature-toggle-strategies-store-type'; -export interface FeatureConfigurationCacheClient +export interface FeatureConfigurationDeltaClient extends FeatureConfigurationClient { description: string; impressionData: false; } -export interface IClientFeatureToggleCacheReadModel { +export interface IClientFeatureToggleDeltaReadModel { getAll( featureQuery: IFeatureToggleQuery, - ): Promise; + ): Promise; } diff --git a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-read-model.ts b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-read-model.ts similarity index 91% rename from src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-read-model.ts rename to src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-read-model.ts index 7bddd95db9..969e21d7f8 100644 --- a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache-read-model.ts +++ b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta-read-model.ts @@ -5,21 +5,21 @@ import Raw = Knex.Raw; import type EventEmitter from 'events'; import { ALL_PROJECTS, ensureStringValue, mapValues } from '../../../util'; import type { - FeatureConfigurationCacheClient, - IClientFeatureToggleCacheReadModel, -} from './client-feature-toggle-cache-read-model-type'; + FeatureConfigurationDeltaClient, + IClientFeatureToggleDeltaReadModel, +} from './client-feature-toggle-delta-read-model-type'; import type { Db } from '../../../db/db'; import { DB_TIME, - type IFeatureToggleCacheQuery, + type IFeatureToggleDeltaQuery, type IStrategyConfig, type PartialDeep, } from '../../../internals'; import metricsHelper from '../../../util/metrics-helper'; import FeatureToggleStore from '../../feature-toggle/feature-toggle-store'; -export default class ClientFeatureToggleCacheReadModel - implements IClientFeatureToggleCacheReadModel +export default class ClientFeatureToggleDeltaReadModel + implements IClientFeatureToggleDeltaReadModel { private db: Db; @@ -29,14 +29,14 @@ export default class ClientFeatureToggleCacheReadModel this.db = db; this.timer = (action: string) => metricsHelper.wrapTimer(eventBus, DB_TIME, { - store: 'client-feature-toggle-cache-read-model', + store: 'client-feature-toggle-delta-read-model', action, }); } public async getAll( - featureQuery: IFeatureToggleCacheQuery, - ): Promise { + featureQuery: IFeatureToggleDeltaQuery, + ): Promise { const environment = featureQuery.environment; const stopTimer = this.timer(`getAll`); @@ -128,7 +128,7 @@ export default class ClientFeatureToggleCacheReadModel stopTimer(); const featureToggles = rows.reduce((acc, r) => { - const feature: PartialDeep = acc[ + const feature: PartialDeep = acc[ r.name ] ?? { strategies: [], @@ -168,7 +168,7 @@ export default class ClientFeatureToggleCacheReadModel return acc; }, {}); - const features: FeatureConfigurationCacheClient[] = + const features: FeatureConfigurationDeltaClient[] = Object.values(featureToggles); // strip away unwanted properties @@ -193,7 +193,7 @@ export default class ClientFeatureToggleCacheReadModel } private addSegmentIdsToStrategy( - feature: PartialDeep, + feature: PartialDeep, row: Record, ) { const strategy = feature.strategies?.find( @@ -222,7 +222,7 @@ export default class ClientFeatureToggleCacheReadModel } private isUnseenStrategyRow( - feature: PartialDeep, + feature: PartialDeep, row: Record, ): boolean { return ( @@ -232,7 +232,7 @@ export default class ClientFeatureToggleCacheReadModel } private addSegmentToStrategy( - feature: PartialDeep, + feature: PartialDeep, row: Record, ) { feature.strategies diff --git a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache.test.ts b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta.test.ts similarity index 99% rename from src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache.test.ts rename to src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta.test.ts index 5fd8302ad6..e9e597a504 100644 --- a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache.test.ts +++ b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta.test.ts @@ -1,4 +1,4 @@ -import { calculateRequiredClientRevision } from './client-feature-toggle-cache'; +import { calculateRequiredClientRevision } from './client-feature-toggle-delta'; const mockAdd = (params): any => { const base = { diff --git a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache.ts b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta.ts similarity index 81% rename from src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache.ts rename to src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta.ts index 45d83a3029..9237b32ba6 100644 --- a/src/lib/features/client-feature-toggles/cache/client-feature-toggle-cache.ts +++ b/src/lib/features/client-feature-toggles/delta/client-feature-toggle-delta.ts @@ -1,24 +1,24 @@ import type { IEventStore, - IFeatureToggleCacheQuery, + IFeatureToggleDeltaQuery, IFeatureToggleQuery, IFlagResolver, } from '../../../types'; import type ConfigurationRevisionService from '../../feature-toggle/configuration-revision-service'; import { UPDATE_REVISION } from '../../feature-toggle/configuration-revision-service'; -import { RevisionCache } from './revision-cache'; +import { RevisionDelta } from './revision-delta'; import type { - FeatureConfigurationCacheClient, - IClientFeatureToggleCacheReadModel, -} from './client-feature-toggle-cache-read-model-type'; + FeatureConfigurationDeltaClient, + IClientFeatureToggleDeltaReadModel, +} from './client-feature-toggle-delta-read-model-type'; type DeletedFeature = { name: string; project: string; }; -export type RevisionCacheEntry = { - updated: FeatureConfigurationCacheClient[]; +export type RevisionDeltaEntry = { + updated: FeatureConfigurationDeltaClient[]; revisionId: number; removed: DeletedFeature[]; }; @@ -29,7 +29,7 @@ export type Revision = { removed: DeletedFeature[]; }; -type Revisions = Record; +type Revisions = Record; const applyRevision = (first: Revision, last: Revision): Revision => { const updatedMap = new Map( @@ -91,10 +91,10 @@ export const calculateRequiredClientRevision = ( return projectFeatureRevisions.reduce(applyRevision); }; -export class ClientFeatureToggleCache { - private clientFeatureToggleCacheReadModel: IClientFeatureToggleCacheReadModel; +export class ClientFeatureToggleDelta { + private clientFeatureToggleDeltaReadModel: IClientFeatureToggleDeltaReadModel; - private cache: Revisions = {}; + private delta: Revisions = {}; private eventStore: IEventStore; @@ -107,18 +107,18 @@ export class ClientFeatureToggleCache { private configurationRevisionService: ConfigurationRevisionService; constructor( - clientFeatureToggleCacheReadModel: IClientFeatureToggleCacheReadModel, + clientFeatureToggleDeltaReadModel: IClientFeatureToggleDeltaReadModel, eventStore: IEventStore, configurationRevisionService: ConfigurationRevisionService, flagResolver: IFlagResolver, ) { this.eventStore = eventStore; this.configurationRevisionService = configurationRevisionService; - this.clientFeatureToggleCacheReadModel = - clientFeatureToggleCacheReadModel; + this.clientFeatureToggleDeltaReadModel = + clientFeatureToggleDeltaReadModel; this.flagResolver = flagResolver; this.onUpdateRevisionEvent = this.onUpdateRevisionEvent.bind(this); - this.cache = {}; + this.delta = {}; this.initRevisionId(); this.configurationRevisionService.on( @@ -135,29 +135,29 @@ export class ClientFeatureToggleCache { async getDelta( sdkRevisionId: number | undefined, query: IFeatureToggleQuery, - ): Promise { + ): Promise { const projects = query.project ? query.project : ['*']; const environment = query.environment ? query.environment : 'default'; // TODO: filter by tags, what is namePrefix? anything else? const requiredRevisionId = sdkRevisionId || 0; - const hasCache = this.cache[environment] !== undefined; + const hasDelta = this.delta[environment] !== undefined; - if (!hasCache) { - await this.initEnvironmentCache(environment); + if (!hasDelta) { + await this.initEnvironmentDelta(environment); } // Should get the latest state if revision does not exist or if sdkRevision is not present - // We should be able to do this without going to the database by merging revisions from the cache with + // We should be able to do this without going to the database by merging revisions from the delta with // the base case const firstTimeCalling = !sdkRevisionId; if ( firstTimeCalling || (sdkRevisionId && sdkRevisionId !== this.currentRevisionId && - !this.cache[environment].hasRevision(sdkRevisionId)) + !this.delta[environment].hasRevision(sdkRevisionId)) ) { - //TODO: populate cache based on this? + //TODO: populate delta based on this? return { revisionId: this.currentRevisionId, // @ts-ignore @@ -170,7 +170,7 @@ export class ClientFeatureToggleCache { return undefined; } - const environmentRevisions = this.cache[environment].getRevisions(); + const environmentRevisions = this.delta[environment].getRevisions(); const compressedRevision = calculateRequiredClientRevision( environmentRevisions, @@ -188,7 +188,7 @@ export class ClientFeatureToggleCache { } public async listenToRevisionChange() { - const keys = Object.keys(this.cache); + const keys = Object.keys(this.delta); if (keys.length === 0) return; const latestRevision = @@ -221,7 +221,7 @@ export class ClientFeatureToggleCache { environment, changedToggles, ); - this.cache[environment].addRevision({ + this.delta[environment].addRevision({ updated: newToggles, revisionId: latestRevision, removed, @@ -234,7 +234,7 @@ export class ClientFeatureToggleCache { async getChangedToggles( environment: string, toggles: string[], - ): Promise { + ): Promise { const foundToggles = await this.getClientFeatures({ toggleNames: toggles, environment, @@ -242,7 +242,7 @@ export class ClientFeatureToggleCache { return foundToggles; } - public async initEnvironmentCache(environment: string) { + public async initEnvironmentDelta(environment: string) { // Todo: replace with method that gets all features for an environment const baseFeatures = await this.getClientFeatures({ environment, @@ -251,7 +251,7 @@ export class ClientFeatureToggleCache { this.currentRevisionId = await this.configurationRevisionService.getMaxRevisionId(); - const cache = new RevisionCache([ + const delta = new RevisionDelta([ { revisionId: this.currentRevisionId, updated: baseFeatures, @@ -259,14 +259,14 @@ export class ClientFeatureToggleCache { }, ]); - this.cache[environment] = cache; + this.delta[environment] = delta; } async getClientFeatures( - query: IFeatureToggleCacheQuery, - ): Promise { + query: IFeatureToggleDeltaQuery, + ): Promise { const result = - await this.clientFeatureToggleCacheReadModel.getAll(query); + await this.clientFeatureToggleDeltaReadModel.getAll(query); return result; } } diff --git a/src/lib/features/client-feature-toggles/cache/createClientFeatureToggleCache.ts b/src/lib/features/client-feature-toggles/delta/createClientFeatureToggleDelta.ts similarity index 54% rename from src/lib/features/client-feature-toggles/cache/createClientFeatureToggleCache.ts rename to src/lib/features/client-feature-toggles/delta/createClientFeatureToggleDelta.ts index 33f06aa63a..78f0d52f5a 100644 --- a/src/lib/features/client-feature-toggles/cache/createClientFeatureToggleCache.ts +++ b/src/lib/features/client-feature-toggles/delta/createClientFeatureToggleDelta.ts @@ -1,30 +1,30 @@ -import { ClientFeatureToggleCache } from './client-feature-toggle-cache'; +import { ClientFeatureToggleDelta } from './client-feature-toggle-delta'; import EventStore from '../../events/event-store'; import ConfigurationRevisionService from '../../feature-toggle/configuration-revision-service'; import type { IUnleashConfig } from '../../../types'; import type { Db } from '../../../db/db'; -import ClientFeatureToggleCacheReadModel from './client-feature-toggle-cache-read-model'; +import ClientFeatureToggleDeltaReadModel from './client-feature-toggle-delta-read-model'; -export const createClientFeatureToggleCache = ( +export const createClientFeatureToggleDelta = ( db: Db, config: IUnleashConfig, -): ClientFeatureToggleCache => { +): ClientFeatureToggleDelta => { const { getLogger, eventBus, flagResolver } = config; const eventStore = new EventStore(db, getLogger); - const clientFeatureToggleCacheReadModel = - new ClientFeatureToggleCacheReadModel(db, eventBus); + const clientFeatureToggleDeltaReadModel = + new ClientFeatureToggleDeltaReadModel(db, eventBus); const configurationRevisionService = ConfigurationRevisionService.getInstance({ eventStore }, config); - const clientFeatureToggleCache = new ClientFeatureToggleCache( - clientFeatureToggleCacheReadModel, + const clientFeatureToggleDelta = new ClientFeatureToggleDelta( + clientFeatureToggleDeltaReadModel, eventStore, configurationRevisionService, flagResolver, ); - return clientFeatureToggleCache; + return clientFeatureToggleDelta; }; diff --git a/src/lib/features/client-feature-toggles/cache/revision-cache.test.ts b/src/lib/features/client-feature-toggles/delta/revision-delta.test.ts similarity index 95% rename from src/lib/features/client-feature-toggles/cache/revision-cache.test.ts rename to src/lib/features/client-feature-toggles/delta/revision-delta.test.ts index 7616feae5a..beacc06332 100644 --- a/src/lib/features/client-feature-toggles/cache/revision-cache.test.ts +++ b/src/lib/features/client-feature-toggles/delta/revision-delta.test.ts @@ -1,5 +1,5 @@ -import { RevisionCache } from './revision-cache'; -import type { Revision } from './client-feature-toggle-cache'; +import { RevisionDelta } from './revision-delta'; +import type { Revision } from './client-feature-toggle-delta'; describe('RevisionCache', () => { it('should create a new base when trying to add a new revision at the max limit', () => { @@ -63,7 +63,7 @@ describe('RevisionCache', () => { ]; const maxLength = 2; - const deltaCache = new RevisionCache(initialRevisions, maxLength); + const deltaCache = new RevisionDelta(initialRevisions, maxLength); // Add a new revision to trigger changeBase deltaCache.addRevision({ diff --git a/src/lib/features/client-feature-toggles/cache/revision-cache.ts b/src/lib/features/client-feature-toggles/delta/revision-delta.ts similarity index 63% rename from src/lib/features/client-feature-toggles/cache/revision-cache.ts rename to src/lib/features/client-feature-toggles/delta/revision-delta.ts index 433a203941..da8c553d1a 100644 --- a/src/lib/features/client-feature-toggles/cache/revision-cache.ts +++ b/src/lib/features/client-feature-toggles/delta/revision-delta.ts @@ -1,4 +1,4 @@ -import type { Revision } from './client-feature-toggle-cache'; +import type { Revision } from './client-feature-toggle-delta'; const mergeWithoutDuplicates = (arr1: any[], arr2: any[]) => { const map = new Map(); @@ -8,41 +8,41 @@ const mergeWithoutDuplicates = (arr1: any[], arr2: any[]) => { return Array.from(map.values()); }; -export class RevisionCache { - private cache: Revision[]; +export class RevisionDelta { + private delta: Revision[]; private maxLength: number; constructor(data: Revision[] = [], maxLength: number = 100) { - this.cache = data; + this.delta = data; this.maxLength = maxLength; } public addRevision(revision: Revision): void { - if (this.cache.length >= this.maxLength) { + if (this.delta.length >= this.maxLength) { this.changeBase(); } - this.cache = [...this.cache, revision]; + this.delta = [...this.delta, revision]; } public getRevisions(): Revision[] { - return this.cache; + return this.delta; } public hasRevision(revisionId: number): boolean { - return this.cache.some( + return this.delta.some( (revision) => revision.revisionId === revisionId, ); } private changeBase(): void { - if (!(this.cache.length >= 2)) return; - const base = this.cache[0]; - const newBase = this.cache[1]; + if (!(this.delta.length >= 2)) return; + const base = this.delta[0]; + const newBase = this.delta[1]; newBase.removed = mergeWithoutDuplicates(base.removed, newBase.removed); newBase.updated = mergeWithoutDuplicates(base.updated, newBase.updated); - this.cache = [newBase, ...this.cache.slice(2)]; + this.delta = [newBase, ...this.delta.slice(2)]; } } diff --git a/src/lib/routes/client-api/index.ts b/src/lib/routes/client-api/index.ts index 60ef1d7417..6fa6f3197d 100644 --- a/src/lib/routes/client-api/index.ts +++ b/src/lib/routes/client-api/index.ts @@ -3,7 +3,7 @@ import FeatureController from '../../features/client-feature-toggles/client-feat import MetricsController from '../../features/metrics/instance/metrics'; import RegisterController from '../../features/metrics/instance/register'; import type { IUnleashConfig, IUnleashServices } from '../../types'; -import ClientFeatureToggleDeltaController from '../../features/client-feature-toggles/cache/client-feature-toggle-cache-controller'; +import ClientFeatureToggleDeltaController from '../../features/client-feature-toggles/delta/client-feature-toggle-delta-controller'; export default class ClientApi extends Controller { constructor(config: IUnleashConfig, services: IUnleashServices) { diff --git a/src/lib/types/model.ts b/src/lib/types/model.ts index fd855171f0..cd97dd91b4 100644 --- a/src/lib/types/model.ts +++ b/src/lib/types/model.ts @@ -345,7 +345,7 @@ export interface IFeatureToggleQuery { inlineSegmentConstraints?: boolean; } -export interface IFeatureToggleCacheQuery extends IFeatureToggleQuery { +export interface IFeatureToggleDeltaQuery extends IFeatureToggleQuery { toggleNames?: string[]; environment: string; }