Skip to content

Commit 64489f7

Browse files
committed
feat: Implement cache file streaming with progress logging
If cache files get large enough to cause noticeable delay it will be helpful to log progress
1 parent 92d5d36 commit 64489f7

File tree

2 files changed

+41
-28
lines changed

2 files changed

+41
-28
lines changed

src/backend/common/Cache.ts

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export class MSCache {
114114
logger.debug(`Building file cache from ${path.join(config.connection, `${ns}.cache`)}`);
115115

116116
try {
117-
const [keyvFile] = initFileCache({ ...config, cacheDir: config.connection, cacheId: `${ns}.cache` }, logger);
117+
const [keyvFile] = await initFileCache({ ...config, cacheDir: config.connection, cacheId: `${ns}.cache` }, logger);
118118
secondaryCache = keyvFile;
119119
} catch (e) {
120120
logger.warn(e);
@@ -177,38 +177,57 @@ export const flatCacheCreate = (opts: FlatCacheOptions) => {
177177
});
178178
}
179179

180-
export const flatCacheLoad = (flatCache: FlatCache, logger: MaybeLogger): void => {
180+
export const flatCacheLoad = async (flatCache: FlatCache, logger: MaybeLogger): Promise<void> => {
181181

182182
const cachePath = path.join(flatCache.cacheDir, flatCache.cacheId);
183183
try {
184184
fileOrDirectoryIsWriteable(cachePath);
185185
} catch (e) {
186-
new Error(`Unable to use path for file cache at ${cachePath}`, { cause: e })
186+
throw new Error(`Unable to use path for file cache at ${cachePath}`, { cause: e })
187187
}
188188

189-
let loadError: Error;
189+
const streamPromise = new Promise((resolve, reject) => {
190+
flatCache.loadFileStream(cachePath, (progress: number, total: number) => {
191+
logger.debug(`Loading ${progress}/${total} chunks...`);
192+
}, () => {
193+
resolve(true);
194+
}, (err: Error) => {
195+
reject(err);
196+
});
197+
});
190198

191-
const onlySaveError = (e: Error) => {
192-
loadError = e;
193-
}
194-
flatCache.on('error', onlySaveError);
195199
try {
196-
logger.debug('Loading cache from file...');
197-
flatCache.load();
198-
if (loadError !== undefined) {
199-
throw loadError;
200-
}
200+
await streamPromise;
201201
logger.debug(`File cache loaded`);
202-
flatCache.off('error', onlySaveError);
202+
return;
203203
} catch (e) {
204-
throw new Error(`Unable to use file cache at ${cachePath}`, { cause: e });
204+
if (null !== e.message.match(/Cache file .+ does not exist/)) {
205+
let loadError: Error;
206+
try {
207+
const onlySaveError = (e: Error) => {
208+
loadError = e;
209+
};
210+
flatCache.on('error', onlySaveError);
211+
flatCache.load();
212+
if (loadError !== undefined) {
213+
throw loadError;
214+
}
215+
flatCache.off('error', onlySaveError);
216+
logger.debug(`File cache loaded`);
217+
return;
218+
} catch (e) {
219+
throw new Error(`Unable to use file cache at ${cachePath}`, { cause: e });
220+
}
221+
} else {
222+
throw new Error(`Unable to use file cache at ${cachePath}`, { cause: e });
223+
}
205224
}
206225
}
207226

208-
export const initFileCache = (opts: FlatCacheOptions = {}, logger: MaybeLogger = new MaybeLogger()): [Keyv | KeyvStoreAdapter | undefined, FlatCache | undefined] => {
227+
export const initFileCache = async (opts: FlatCacheOptions = {}, logger: MaybeLogger = new MaybeLogger()): Promise<[Keyv | KeyvStoreAdapter | undefined, FlatCache | undefined]> => {
209228
const flatCache = flatCacheCreate(opts);
210229
try {
211-
flatCacheLoad(flatCache, logger);
230+
await flatCacheLoad(flatCache, logger);
212231
flatCache.on('error', (e) => {
213232
logger.warn(e);
214233
});

src/backend/tests/cache/cache.test.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,27 +162,21 @@ describe('#Caching', function () {
162162

163163
const root = getRoot();
164164
root.upsert({ cache: () => () => new MSCache(loggerTest, { scrobble: { provider: 'file', connection: process.cwd(), persistInterval: 100 } }) });
165-
root.items.cache().init();
166165

167166
const test = new TestScrobbler();
168167
await test.initialize();
169-
const play = generatePlay();
170-
test.queueScrobble(play, 'testSource');
168+
const plays = generatePlays(100);
169+
test.queueScrobble(plays, 'testSource');
170+
const queued = test.queuedScrobbles.map(x => x.play);
171171
await sleep(101);
172172
const dirContents = await promises.readdir('.');
173173
const hasCache = dirContents.some(x => x === 'ms-scrobble.cache');
174174
expect(hasCache).is.true;
175175

176-
// reinit cache
177-
root.upsert({ cache: () => () => new MSCache(loggerTest, { scrobble: { provider: 'file', connection: process.cwd(), persistInterval: 100 } }) });
178-
const newCache = root.items.cache();
179-
expect(newCache.cacheScrobble).to.be.undefined;
180-
newCache.init();
181-
182176
const newTest = new TestScrobbler();
183177
await newTest.initialize();
184-
expect(newTest.queuedScrobbles.length).to.eq(1);
185-
expect(newTest.queuedScrobbles[0].play.data.track).to.eq(play.data.track);
178+
expect(newTest.queuedScrobbles.length).to.eq(plays.length);
179+
expect(newTest.queuedScrobbles[0].play.data.track).to.eq(queued[0].data.track);
186180

187181
}, { unsafeCleanup: true });
188182

0 commit comments

Comments
 (0)