Skip to content

Commit e1190c6

Browse files
authored
[FSSDK-11505] update cache interface (#1051)
1 parent db81531 commit e1190c6

22 files changed

+400
-395
lines changed

lib/core/decision_service/cmab/cmab_service.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { LoggerFacade } from "../../../logging/logger";
1818
import { IOptimizelyUserContext } from "../../../optimizely_user_context";
1919
import { ProjectConfig } from "../../../project_config/project_config"
2020
import { OptimizelyDecideOption, UserAttributes } from "../../../shared_types"
21-
import { Cache } from "../../../utils/cache/cache";
21+
import { Cache, CacheWithRemove } from "../../../utils/cache/cache";
2222
import { CmabClient } from "./cmab_client";
2323
import { v4 as uuidV4 } from 'uuid';
2424
import murmurhash from "murmurhash";
@@ -53,12 +53,12 @@ export type CmabCacheValue = {
5353

5454
export type CmabServiceOptions = {
5555
logger?: LoggerFacade;
56-
cmabCache: Cache<CmabCacheValue>;
56+
cmabCache: CacheWithRemove<CmabCacheValue>;
5757
cmabClient: CmabClient;
5858
}
5959

6060
export class DefaultCmabService implements CmabService {
61-
private cmabCache: Cache<CmabCacheValue>;
61+
private cmabCache: CacheWithRemove<CmabCacheValue>;
6262
private cmabClient: CmabClient;
6363
private logger?: LoggerFacade;
6464

@@ -81,7 +81,7 @@ export class DefaultCmabService implements CmabService {
8181
}
8282

8383
if (options[OptimizelyDecideOption.RESET_CMAB_CACHE]) {
84-
this.cmabCache.clear();
84+
this.cmabCache.reset();
8585
}
8686

8787
const cacheKey = this.getCacheKey(userContext.getUserId(), ruleId);
@@ -90,7 +90,7 @@ export class DefaultCmabService implements CmabService {
9090
this.cmabCache.remove(cacheKey);
9191
}
9292

93-
const cachedValue = await this.cmabCache.get(cacheKey);
93+
const cachedValue = await this.cmabCache.lookup(cacheKey);
9494

9595
const attributesJson = JSON.stringify(filteredAttributes, Object.keys(filteredAttributes).sort());
9696
const attributesHash = String(murmurhash.v3(attributesJson));
@@ -104,7 +104,7 @@ export class DefaultCmabService implements CmabService {
104104
}
105105

106106
const variation = await this.fetchDecision(ruleId, userContext.getUserId(), filteredAttributes);
107-
this.cmabCache.set(cacheKey, {
107+
this.cmabCache.save(cacheKey, {
108108
attributesHash,
109109
variationId: variation.variationId,
110110
cmabUuid: variation.cmabUuid,

lib/event_processor/batch_event_processor.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2024, Optimizely
2+
* Copyright 2024-2025, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import { EventProcessor, ProcessableEvent } from "./event_processor";
18-
import { Cache } from "../utils/cache/cache";
18+
import { getBatchedAsync, getBatchedSync, Store } from "../utils/cache/store";
1919
import { EventDispatcher, EventDispatcherResponse, LogEvent } from "./event_dispatcher/event_dispatcher";
2020
import { buildLogEvent } from "./event_builder/log_event";
2121
import { BackoffController, ExponentialBackoff, IntervalRepeater, Repeater } from "../utils/repeater/repeater";
@@ -49,7 +49,7 @@ export type BatchEventProcessorConfig = {
4949
dispatchRepeater: Repeater,
5050
failedEventRepeater?: Repeater,
5151
batchSize: number,
52-
eventStore?: Cache<EventWithId>,
52+
eventStore?: Store<EventWithId>,
5353
eventDispatcher: EventDispatcher,
5454
closingEventDispatcher?: EventDispatcher,
5555
logger?: LoggerFacade,
@@ -69,7 +69,7 @@ export class BatchEventProcessor extends BaseService implements EventProcessor {
6969
private closingEventDispatcher?: EventDispatcher;
7070
private eventQueue: EventWithId[] = [];
7171
private batchSize: number;
72-
private eventStore?: Cache<EventWithId>;
72+
private eventStore?: Store<EventWithId>;
7373
private dispatchRepeater: Repeater;
7474
private failedEventRepeater?: Repeater;
7575
private idGenerator: IdGenerator = new IdGenerator();
@@ -114,7 +114,9 @@ export class BatchEventProcessor extends BaseService implements EventProcessor {
114114
(k) => !this.dispatchingEventIds.has(k) && !this.eventQueue.find((e) => e.id === k)
115115
);
116116

117-
const events = await this.eventStore.getBatched(keys);
117+
const events = await (this.eventStore.operation === 'sync' ?
118+
getBatchedSync(this.eventStore, keys) : getBatchedAsync(this.eventStore, keys));
119+
118120
const failedEvents: EventWithId[] = [];
119121
events.forEach((e) => {
120122
if(e) {

lib/event_processor/event_processor_factory.browser.spec.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2024, Optimizely
2+
* Copyright 2024-2025, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -41,14 +41,14 @@ vi.mock('../utils/cache/local_storage_cache.browser', () => {
4141
return { LocalStorageCache: vi.fn() };
4242
});
4343

44-
vi.mock('../utils/cache/cache', () => {
45-
return { SyncPrefixCache: vi.fn() };
44+
vi.mock('../utils/cache/store', () => {
45+
return { SyncPrefixStore: vi.fn() };
4646
});
4747

4848

4949
import defaultEventDispatcher from './event_dispatcher/default_dispatcher.browser';
5050
import { LocalStorageCache } from '../utils/cache/local_storage_cache.browser';
51-
import { SyncPrefixCache } from '../utils/cache/cache';
51+
import { SyncPrefixStore } from '../utils/cache/store';
5252
import { createForwardingEventProcessor, createBatchEventProcessor } from './event_processor_factory.browser';
5353
import { EVENT_STORE_PREFIX, extractEventProcessor, FAILED_EVENT_RETRY_INTERVAL } from './event_processor_factory';
5454
import sendBeaconEventDispatcher from './event_dispatcher/send_beacon_dispatcher.browser';
@@ -85,21 +85,21 @@ describe('createForwardingEventProcessor', () => {
8585
describe('createBatchEventProcessor', () => {
8686
const mockGetOpaqueBatchEventProcessor = vi.mocked(getOpaqueBatchEventProcessor);
8787
const MockLocalStorageCache = vi.mocked(LocalStorageCache);
88-
const MockSyncPrefixCache = vi.mocked(SyncPrefixCache);
88+
const MockSyncPrefixStore = vi.mocked(SyncPrefixStore);
8989

9090
beforeEach(() => {
9191
mockGetOpaqueBatchEventProcessor.mockClear();
9292
MockLocalStorageCache.mockClear();
93-
MockSyncPrefixCache.mockClear();
93+
MockSyncPrefixStore.mockClear();
9494
});
9595

96-
it('uses LocalStorageCache and SyncPrefixCache to create eventStore', () => {
96+
it('uses LocalStorageCache and SyncPrefixStore to create eventStore', () => {
9797
const processor = createBatchEventProcessor({});
9898
expect(Object.is(processor, mockGetOpaqueBatchEventProcessor.mock.results[0].value)).toBe(true);
9999
const eventStore = mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore;
100-
expect(Object.is(eventStore, MockSyncPrefixCache.mock.results[0].value)).toBe(true);
100+
expect(Object.is(eventStore, MockSyncPrefixStore.mock.results[0].value)).toBe(true);
101101

102-
const [cache, prefix, transformGet, transformSet] = MockSyncPrefixCache.mock.calls[0];
102+
const [cache, prefix, transformGet, transformSet] = MockSyncPrefixStore.mock.calls[0];
103103
expect(Object.is(cache, MockLocalStorageCache.mock.results[0].value)).toBe(true);
104104
expect(prefix).toBe(EVENT_STORE_PREFIX);
105105

lib/event_processor/event_processor_factory.browser.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
import defaultEventDispatcher from './event_dispatcher/default_dispatcher.browser';
2828
import sendBeaconEventDispatcher from './event_dispatcher/send_beacon_dispatcher.browser';
2929
import { LocalStorageCache } from '../utils/cache/local_storage_cache.browser';
30-
import { SyncPrefixCache } from '../utils/cache/cache';
30+
import { SyncPrefixStore } from '../utils/cache/store';
3131
import { EVENT_STORE_PREFIX, FAILED_EVENT_RETRY_INTERVAL } from './event_processor_factory';
3232

3333
export const DEFAULT_EVENT_BATCH_SIZE = 10;
@@ -45,7 +45,7 @@ export const createBatchEventProcessor = (
4545
options: BatchEventProcessorOptions = {}
4646
): OpaqueEventProcessor => {
4747
const localStorageCache = new LocalStorageCache<EventWithId>();
48-
const eventStore = new SyncPrefixCache<EventWithId, EventWithId>(
48+
const eventStore = new SyncPrefixStore<EventWithId, EventWithId>(
4949
localStorageCache, EVENT_STORE_PREFIX,
5050
identity,
5151
identity,

lib/event_processor/event_processor_factory.node.spec.ts

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2024, Optimizely
2+
* Copyright 2024-2025, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,16 +39,16 @@ vi.mock('../utils/cache/async_storage_cache.react_native', () => {
3939
return { AsyncStorageCache: vi.fn() };
4040
});
4141

42-
vi.mock('../utils/cache/cache', () => {
43-
return { SyncPrefixCache: vi.fn(), AsyncPrefixCache: vi.fn() };
42+
vi.mock('../utils/cache/store', () => {
43+
return { SyncPrefixStore: vi.fn(), AsyncPrefixStore: vi.fn() };
4444
});
4545

4646
import { createBatchEventProcessor, createForwardingEventProcessor } from './event_processor_factory.node';
4747
import { getForwardingEventProcessor } from './forwarding_event_processor';
4848
import nodeDefaultEventDispatcher from './event_dispatcher/default_dispatcher.node';
4949
import { EVENT_STORE_PREFIX, extractEventProcessor, FAILED_EVENT_RETRY_INTERVAL } from './event_processor_factory';
5050
import { getOpaqueBatchEventProcessor } from './event_processor_factory';
51-
import { AsyncCache, AsyncPrefixCache, SyncCache, SyncPrefixCache } from '../utils/cache/cache';
51+
import { AsyncStore, AsyncPrefixStore, SyncStore, SyncPrefixStore } from '../utils/cache/store';
5252
import { AsyncStorageCache } from '../utils/cache/async_storage_cache.react_native';
5353

5454
describe('createForwardingEventProcessor', () => {
@@ -80,14 +80,14 @@ describe('createForwardingEventProcessor', () => {
8080
describe('createBatchEventProcessor', () => {
8181
const mockGetOpaqueBatchEventProcessor = vi.mocked(getOpaqueBatchEventProcessor);
8282
const MockAsyncStorageCache = vi.mocked(AsyncStorageCache);
83-
const MockSyncPrefixCache = vi.mocked(SyncPrefixCache);
84-
const MockAsyncPrefixCache = vi.mocked(AsyncPrefixCache);
83+
const MockSyncPrefixStore = vi.mocked(SyncPrefixStore);
84+
const MockAsyncPrefixStore = vi.mocked(AsyncPrefixStore);
8585

8686
beforeEach(() => {
8787
mockGetOpaqueBatchEventProcessor.mockClear();
8888
MockAsyncStorageCache.mockClear();
89-
MockSyncPrefixCache.mockClear();
90-
MockAsyncPrefixCache.mockClear();
89+
MockSyncPrefixStore.mockClear();
90+
MockAsyncPrefixStore.mockClear();
9191
});
9292

9393
it('uses no default event store if no eventStore is provided', () => {
@@ -98,16 +98,16 @@ describe('createBatchEventProcessor', () => {
9898
expect(eventStore).toBe(undefined);
9999
});
100100

101-
it('wraps the provided eventStore in a SyncPrefixCache if a SyncCache is provided as eventStore', () => {
101+
it('wraps the provided eventStore in a SyncPrefixStore if a SyncCache is provided as eventStore', () => {
102102
const eventStore = {
103103
operation: 'sync',
104-
} as SyncCache<string>;
104+
} as SyncStore<string>;
105105

106106
const processor = createBatchEventProcessor({ eventStore });
107107
expect(Object.is(processor, mockGetOpaqueBatchEventProcessor.mock.results[0].value)).toBe(true);
108108

109-
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore).toBe(MockSyncPrefixCache.mock.results[0].value);
110-
const [cache, prefix, transformGet, transformSet] = MockSyncPrefixCache.mock.calls[0];
109+
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore).toBe(MockSyncPrefixStore.mock.results[0].value);
110+
const [cache, prefix, transformGet, transformSet] = MockSyncPrefixStore.mock.calls[0];
111111

112112
expect(cache).toBe(eventStore);
113113
expect(prefix).toBe(EVENT_STORE_PREFIX);
@@ -117,16 +117,16 @@ describe('createBatchEventProcessor', () => {
117117
expect(transformSet({ value: 1 })).toBe('{"value":1}');
118118
});
119119

120-
it('wraps the provided eventStore in a AsyncPrefixCache if a AsyncCache is provided as eventStore', () => {
120+
it('wraps the provided eventStore in a AsyncPrefixStore if a AsyncCache is provided as eventStore', () => {
121121
const eventStore = {
122122
operation: 'async',
123-
} as AsyncCache<string>;
123+
} as AsyncStore<string>;
124124

125125
const processor = createBatchEventProcessor({ eventStore });
126126
expect(Object.is(processor, mockGetOpaqueBatchEventProcessor.mock.results[0].value)).toBe(true);
127127

128-
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore).toBe(MockAsyncPrefixCache.mock.results[0].value);
129-
const [cache, prefix, transformGet, transformSet] = MockAsyncPrefixCache.mock.calls[0];
128+
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore).toBe(MockAsyncPrefixStore.mock.results[0].value);
129+
const [cache, prefix, transformGet, transformSet] = MockAsyncPrefixStore.mock.calls[0];
130130

131131
expect(cache).toBe(eventStore);
132132
expect(prefix).toBe(EVENT_STORE_PREFIX);

lib/event_processor/event_processor_factory.react_native.spec.ts

+20-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2024, Optimizely
2+
* Copyright 2024-2025, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,8 +40,8 @@ vi.mock('../utils/cache/async_storage_cache.react_native', () => {
4040
return { AsyncStorageCache: vi.fn() };
4141
});
4242

43-
vi.mock('../utils/cache/cache', () => {
44-
return { SyncPrefixCache: vi.fn(), AsyncPrefixCache: vi.fn() };
43+
vi.mock('../utils/cache/store', () => {
44+
return { SyncPrefixStore: vi.fn(), AsyncPrefixStore: vi.fn() };
4545
});
4646

4747
vi.mock('@react-native-community/netinfo', () => {
@@ -79,7 +79,7 @@ import { getForwardingEventProcessor } from './forwarding_event_processor';
7979
import defaultEventDispatcher from './event_dispatcher/default_dispatcher.browser';
8080
import { EVENT_STORE_PREFIX, extractEventProcessor, FAILED_EVENT_RETRY_INTERVAL, getPrefixEventStore } from './event_processor_factory';
8181
import { getOpaqueBatchEventProcessor } from './event_processor_factory';
82-
import { AsyncCache, AsyncPrefixCache, SyncCache, SyncPrefixCache } from '../utils/cache/cache';
82+
import { AsyncStore, AsyncPrefixStore, SyncStore, SyncPrefixStore } from '../utils/cache/store';
8383
import { AsyncStorageCache } from '../utils/cache/async_storage_cache.react_native';
8484
import { ReactNativeNetInfoEventProcessor } from './batch_event_processor.react_native';
8585
import { BatchEventProcessor } from './batch_event_processor';
@@ -115,15 +115,15 @@ describe('createForwardingEventProcessor', () => {
115115
describe('createBatchEventProcessor', () => {
116116
const mockGetOpaqueBatchEventProcessor = vi.mocked(getOpaqueBatchEventProcessor);
117117
const MockAsyncStorageCache = vi.mocked(AsyncStorageCache);
118-
const MockSyncPrefixCache = vi.mocked(SyncPrefixCache);
119-
const MockAsyncPrefixCache = vi.mocked(AsyncPrefixCache);
118+
const MockSyncPrefixStore = vi.mocked(SyncPrefixStore);
119+
const MockAsyncPrefixStore = vi.mocked(AsyncPrefixStore);
120120

121121
beforeEach(() => {
122122
isNetInfoAvailable = false;
123123
mockGetOpaqueBatchEventProcessor.mockClear();
124124
MockAsyncStorageCache.mockClear();
125-
MockSyncPrefixCache.mockClear();
126-
MockAsyncPrefixCache.mockClear();
125+
MockSyncPrefixStore.mockClear();
126+
MockAsyncPrefixStore.mockClear();
127127
});
128128

129129
it('returns an instance of ReacNativeNetInfoEventProcessor if netinfo can be required', async () => {
@@ -140,14 +140,14 @@ describe('createBatchEventProcessor', () => {
140140
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][1]).toBe(BatchEventProcessor);
141141
});
142142

143-
it('uses AsyncStorageCache and AsyncPrefixCache to create eventStore if no eventStore is provided', () => {
143+
it('uses AsyncStorageCache and AsyncPrefixStore to create eventStore if no eventStore is provided', () => {
144144
const processor = createBatchEventProcessor({});
145145

146146
expect(Object.is(processor, mockGetOpaqueBatchEventProcessor.mock.results[0].value)).toBe(true);
147147
const eventStore = mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore;
148-
expect(Object.is(eventStore, MockAsyncPrefixCache.mock.results[0].value)).toBe(true);
148+
expect(Object.is(eventStore, MockAsyncPrefixStore.mock.results[0].value)).toBe(true);
149149

150-
const [cache, prefix, transformGet, transformSet] = MockAsyncPrefixCache.mock.calls[0];
150+
const [cache, prefix, transformGet, transformSet] = MockAsyncPrefixStore.mock.calls[0];
151151
expect(Object.is(cache, MockAsyncStorageCache.mock.results[0].value)).toBe(true);
152152
expect(prefix).toBe(EVENT_STORE_PREFIX);
153153

@@ -177,7 +177,7 @@ describe('createBatchEventProcessor', () => {
177177
isAsyncStorageAvailable = false;
178178
const eventStore = {
179179
operation: 'sync',
180-
} as SyncCache<string>;
180+
} as SyncStore<string>;
181181

182182
const { AsyncStorageCache } = await vi.importActual<
183183
typeof import('../utils/cache/async_storage_cache.react_native')
@@ -192,16 +192,16 @@ describe('createBatchEventProcessor', () => {
192192
isAsyncStorageAvailable = true;
193193
});
194194

195-
it('wraps the provided eventStore in a SyncPrefixCache if a SyncCache is provided as eventStore', () => {
195+
it('wraps the provided eventStore in a SyncPrefixStore if a SyncCache is provided as eventStore', () => {
196196
const eventStore = {
197197
operation: 'sync',
198-
} as SyncCache<string>;
198+
} as SyncStore<string>;
199199

200200
const processor = createBatchEventProcessor({ eventStore });
201201
expect(Object.is(processor, mockGetOpaqueBatchEventProcessor.mock.results[0].value)).toBe(true);
202202

203-
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore).toBe(MockSyncPrefixCache.mock.results[0].value);
204-
const [cache, prefix, transformGet, transformSet] = MockSyncPrefixCache.mock.calls[0];
203+
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore).toBe(MockSyncPrefixStore.mock.results[0].value);
204+
const [cache, prefix, transformGet, transformSet] = MockSyncPrefixStore.mock.calls[0];
205205

206206
expect(cache).toBe(eventStore);
207207
expect(prefix).toBe(EVENT_STORE_PREFIX);
@@ -211,16 +211,16 @@ describe('createBatchEventProcessor', () => {
211211
expect(transformSet({ value: 1 })).toBe('{"value":1}');
212212
});
213213

214-
it('wraps the provided eventStore in a AsyncPrefixCache if a AsyncCache is provided as eventStore', () => {
214+
it('wraps the provided eventStore in a AsyncPrefixStore if a AsyncCache is provided as eventStore', () => {
215215
const eventStore = {
216216
operation: 'async',
217-
} as AsyncCache<string>;
217+
} as AsyncStore<string>;
218218

219219
const processor = createBatchEventProcessor({ eventStore });
220220
expect(Object.is(processor, mockGetOpaqueBatchEventProcessor.mock.results[0].value)).toBe(true);
221221

222-
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore).toBe(MockAsyncPrefixCache.mock.results[0].value);
223-
const [cache, prefix, transformGet, transformSet] = MockAsyncPrefixCache.mock.calls[0];
222+
expect(mockGetOpaqueBatchEventProcessor.mock.calls[0][0].eventStore).toBe(MockAsyncPrefixStore.mock.results[0].value);
223+
const [cache, prefix, transformGet, transformSet] = MockAsyncPrefixStore.mock.calls[0];
224224

225225
expect(cache).toBe(eventStore);
226226
expect(prefix).toBe(EVENT_STORE_PREFIX);

lib/event_processor/event_processor_factory.react_native.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
wrapEventProcessor,
2626
} from './event_processor_factory';
2727
import { EVENT_STORE_PREFIX, FAILED_EVENT_RETRY_INTERVAL } from './event_processor_factory';
28-
import { AsyncPrefixCache } from '../utils/cache/cache';
28+
import { AsyncPrefixStore } from '../utils/cache/store';
2929
import { BatchEventProcessor, EventWithId } from './batch_event_processor';
3030
import { AsyncStorageCache } from '../utils/cache/async_storage_cache.react_native';
3131
import { ReactNativeNetInfoEventProcessor } from './batch_event_processor.react_native';
@@ -45,7 +45,7 @@ const identity = <T>(v: T): T => v;
4545
const getDefaultEventStore = () => {
4646
const asyncStorageCache = new AsyncStorageCache<EventWithId>();
4747

48-
const eventStore = new AsyncPrefixCache<EventWithId, EventWithId>(
48+
const eventStore = new AsyncPrefixStore<EventWithId, EventWithId>(
4949
asyncStorageCache,
5050
EVENT_STORE_PREFIX,
5151
identity,

0 commit comments

Comments
 (0)