fix(caching): properly respect ttl for all cache levels
This commit is contained in:
		
							
								
								
									
										18
									
								
								test/test.ts
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								test/test.ts
									
									
									
									
									
								
							@@ -21,7 +21,23 @@ tap.test('should cache a value', async () => {
 | 
			
		||||
    })
 | 
			
		||||
  );
 | 
			
		||||
  const result = await testLevelCache.retrieveCacheEntryByKey('mykey');
 | 
			
		||||
  console.log(result);
 | 
			
		||||
  expect(result.contents.toString()).to.equal('heythere');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
tap.test('should respect ttl', async (tools) => {
 | 
			
		||||
  await testLevelCache.storeCacheEntryByKey(
 | 
			
		||||
    'mykey',
 | 
			
		||||
    new CacheEntry({
 | 
			
		||||
      contents: Buffer.from('heythere'),
 | 
			
		||||
      ttl: 1000,
 | 
			
		||||
      typeInfo: 'string',
 | 
			
		||||
    })
 | 
			
		||||
  );
 | 
			
		||||
  const result = await testLevelCache.retrieveCacheEntryByKey('mykey');
 | 
			
		||||
  expect(result.contents.toString()).to.equal('heythere');
 | 
			
		||||
  await tools.delayFor(1100);
 | 
			
		||||
  const result2 = await testLevelCache.retrieveCacheEntryByKey('mykey');
 | 
			
		||||
  expect(result2).to.be.null;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
tap.start();
 | 
			
		||||
 
 | 
			
		||||
@@ -4,22 +4,35 @@ export abstract class AbstractCache {
 | 
			
		||||
  public abstract ready: Promise<void>;
 | 
			
		||||
  public abstract status: 'active' | 'inactive';
 | 
			
		||||
 | 
			
		||||
  // Blobs
 | 
			
		||||
  // Cache Entries
 | 
			
		||||
  /**
 | 
			
		||||
   * store a Blob
 | 
			
		||||
   */
 | 
			
		||||
  public abstract storeCacheEntryByKey(keyArg: string, valueArg: CacheEntry): Promise<void>;
 | 
			
		||||
 | 
			
		||||
  // Cache Entries
 | 
			
		||||
  /**
 | 
			
		||||
   * retrieve cache entry
 | 
			
		||||
   */
 | 
			
		||||
  public abstract retrieveCacheEntryByKey(keyArg: string): Promise<CacheEntry>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * checks for the presence of a key
 | 
			
		||||
   * @param keyArg
 | 
			
		||||
   */
 | 
			
		||||
  public abstract checkKeyPresence(keyArg: string): Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * cleans the cache
 | 
			
		||||
   * delete a key
 | 
			
		||||
   */
 | 
			
		||||
  public abstract clean(): Promise<void>;
 | 
			
		||||
   public abstract deleteCacheEntryByKey(keyArg: string): Promise<void>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * clean the cache
 | 
			
		||||
   */
 | 
			
		||||
  public abstract cleanOutdated(): Promise<void>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * cleans the complete cache
 | 
			
		||||
   */
 | 
			
		||||
  public abstract cleanAll(): Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -51,14 +51,18 @@ export class CacheDiskManager extends AbstractCache {
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async checkKeyPresence(keyArg): Promise<boolean> {
 | 
			
		||||
  public async checkKeyPresence(keyArg: string): Promise<boolean> {
 | 
			
		||||
    return plugins.smartfile.fs.isFile(plugins.path.join(this.fsPath, encodeURIComponent(keyArg)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * cleans the DiskCache directory
 | 
			
		||||
   */
 | 
			
		||||
  public async clean() {
 | 
			
		||||
  public async deleteCacheEntryByKey(keyArg: string) {
 | 
			
		||||
    await plugins.smartfile.fs.remove(plugins.path.join(this.fsPath, encodeURIComponent(keyArg)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  public async cleanOutdated() {}
 | 
			
		||||
 | 
			
		||||
  public async cleanAll() {
 | 
			
		||||
    if (this.status === 'active') {
 | 
			
		||||
      if (plugins.smartfile.fs.isDirectory(this.fsPath)) {
 | 
			
		||||
        await plugins.smartfile.fs.ensureEmptyDir(this.fsPath);
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,13 @@ export class CacheMemoryManager extends AbstractCache {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async clean() {
 | 
			
		||||
  public async deleteCacheEntryByKey(keyArg: string) {
 | 
			
		||||
    this.fastMap.removeFromMap(keyArg);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async cleanOutdated() {}
 | 
			
		||||
 | 
			
		||||
  public async cleanAll() {
 | 
			
		||||
    this.fastMap.clean();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,18 @@ export class CacheS3Manager extends AbstractCache {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async clean() {
 | 
			
		||||
  public async deleteCacheEntryByKey(keyArg: string) {
 | 
			
		||||
    if(this.status === 'active') {
 | 
			
		||||
      await this.s3CacheDir.fastRemove(encodeURIComponent(keyArg));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * clean outdated
 | 
			
		||||
   */
 | 
			
		||||
  public async cleanOutdated() {}
 | 
			
		||||
 | 
			
		||||
  public async cleanAll() {
 | 
			
		||||
    await this.s3CacheDir.deleteWithAllContents();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,9 @@ export class CacheEntry
 | 
			
		||||
  @plugins.smartjson.foldDec()
 | 
			
		||||
  contents: Buffer;
 | 
			
		||||
 | 
			
		||||
  @plugins.smartjson.foldDec()
 | 
			
		||||
  public createdAt: number;
 | 
			
		||||
 | 
			
		||||
  public toStorageJsonString(): string {
 | 
			
		||||
    return this.foldToJson();
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,7 @@ export class LevelCache extends AbstractCache {
 | 
			
		||||
  public async storeCacheEntryByKey(keyArg: string, cacheEntryArg: CacheEntry): Promise<void> {
 | 
			
		||||
    cacheEntryArg.key = keyArg;
 | 
			
		||||
    const targetCache = await this.cacheRouter.getCacheForStoreAction(keyArg, cacheEntryArg);
 | 
			
		||||
    cacheEntryArg.createdAt = Date.now();
 | 
			
		||||
    await targetCache.storeCacheEntryByKey(keyArg, cacheEntryArg);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -73,6 +74,10 @@ export class LevelCache extends AbstractCache {
 | 
			
		||||
    const targetCache = await this.cacheRouter.getCacheForRetrieveAction(keyArg);
 | 
			
		||||
    if (targetCache) {
 | 
			
		||||
      const cacheEntry = await targetCache.retrieveCacheEntryByKey(keyArg);
 | 
			
		||||
      if (cacheEntry.createdAt + cacheEntry.ttl < Date.now()) {
 | 
			
		||||
        await this.deleteCacheEntryByKey(keyArg).catch();
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
      return cacheEntry;
 | 
			
		||||
    } else {
 | 
			
		||||
      return null;
 | 
			
		||||
@@ -87,15 +92,25 @@ export class LevelCache extends AbstractCache {
 | 
			
		||||
    ]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // cache maintenance
 | 
			
		||||
  /**
 | 
			
		||||
   * cleans the cache
 | 
			
		||||
   */
 | 
			
		||||
  public async clean(): Promise<void> {
 | 
			
		||||
  public async deleteCacheEntryByKey(keyArg) {
 | 
			
		||||
    await Promise.all([
 | 
			
		||||
      this.cacheDiskManager.clean(),
 | 
			
		||||
      this.cacheDiskManager.clean(),
 | 
			
		||||
      this.cacheS3Manager.clean(),
 | 
			
		||||
      this.cacheMemoryManager.deleteCacheEntryByKey(keyArg),
 | 
			
		||||
      this.cacheDiskManager.deleteCacheEntryByKey(keyArg),
 | 
			
		||||
      this.cacheS3Manager.deleteCacheEntryByKey(keyArg),
 | 
			
		||||
    ]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // cache maintenance
 | 
			
		||||
  public async cleanOutdated() {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * cleans the complete cache
 | 
			
		||||
   */
 | 
			
		||||
  public async cleanAll(): Promise<void> {
 | 
			
		||||
    await Promise.all([
 | 
			
		||||
      this.cacheDiskManager.cleanAll(),
 | 
			
		||||
      this.cacheDiskManager.cleanAll(),
 | 
			
		||||
      this.cacheS3Manager.cleanAll(),
 | 
			
		||||
    ]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user