Skip to content

Commit

Permalink
Merge pull request #1618 from merico-dev/cache-clear
Browse files Browse the repository at this point in the history
feat(cache): implement content-specific file system caching
  • Loading branch information
GerilLeto authored Feb 18, 2025
2 parents f1968c7 + d8e64ed commit 178165b
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 8 deletions.
13 changes: 13 additions & 0 deletions api/src/api_models/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ApiModel, ApiModelProperty } from 'swagger-express-ts';

@ApiModel({
description: 'Cache clear request object',
name: 'CacheClearRequest',
})
export class CacheClearRequest {
@ApiModelProperty({
description: 'Content id',
required: true,
})
content_id: string;
}
3 changes: 3 additions & 0 deletions api/src/api_models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ import {
SqlSnippetSortObject,
} from './sql_snippet';
import { ApiError, Authentication, FilterObject } from './base';
import { CacheClearRequest } from './cache';

export default {
ApiError,
Expand Down Expand Up @@ -224,4 +225,6 @@ export default {
SqlSnippetListRequest,
SqlSnippetPaginationResponse,
SqlSnippetSortObject,

CacheClearRequest,
};
43 changes: 43 additions & 0 deletions api/src/controller/cache.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { controller, httpPost, interfaces } from 'inversify-express-utils';
import { ApiOperationPost, ApiPath } from 'swagger-express-ts';
import { clearFsCache, clearFsCacheByContentId } from '../utils/fs_cache';
import { CacheClearRequest } from '../api_models/cache';
import express from 'express';
import { validate } from '../middleware/validation';
@ApiPath({
path: '/cache',
name: 'Cache',
})
@controller('/cache')
export class CacheController implements interfaces.Controller {
public static TARGET_NAME = 'Cache';

@ApiOperationPost({
path: '/clear',
description: 'Clear cache',
parameters: {},
responses: {
200: { description: 'SUCCESS' },
},
})
@httpPost('/clear')
public async clear(): Promise<void> {
clearFsCache();
}

@ApiOperationPost({
path: '/clear/dashboard',
description: 'Clear cache by content id',
parameters: {
body: { description: 'Cache clear request', required: true, model: 'CacheClearRequest' },
},
responses: {
200: { description: 'SUCCESS' },
},
})
@httpPost('/clear/dashboard', validate(CacheClearRequest))
public async clearByContentId(req: express.Request): Promise<void> {
const { content_id } = req.body as CacheClearRequest;
clearFsCacheByContentId(content_id);
}
}
6 changes: 6 additions & 0 deletions api/src/controller/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { DashboardContentController } from './dashboard_content.controller';
import { DashboardContentChangelogController } from './dashboard_content_changelog.controller';
import { CustomFunctionController } from './custom_function.controller';
import { SqlSnippetController } from './sql_snippet.controller';
import { CacheController } from './cache.controller';

export function bindControllers(container: Container) {
container
Expand Down Expand Up @@ -86,4 +87,9 @@ export function bindControllers(container: Container) {
.to(SqlSnippetController)
.inSingletonScope()
.whenTargetNamed(SqlSnippetController.TARGET_NAME);
container
.bind<interfaces.Controller>(TYPE.Controller)
.to(CacheController)
.inSingletonScope()
.whenTargetNamed(CacheController.TARGET_NAME);
}
4 changes: 2 additions & 2 deletions api/src/services/query.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ export class QueryService {
const fsCacheEnabled = await isFsCacheEnabled();
const cacheKey = getFsCacheKey(`${parsedType}:${parsedKey}:${q}`);
if (fsCacheEnabled && !refresh_cache) {
const cached = await getFsCache(cacheKey);
const cached = await getFsCache(content_id, cacheKey);
if (cached) {
return cached;
}
Expand All @@ -292,7 +292,7 @@ export class QueryService {
return null;
}
if (fsCacheEnabled) {
await putFsCache(cacheKey, result);
await putFsCache(content_id, cacheKey, result);
}
return result;
}
Expand Down
16 changes: 10 additions & 6 deletions api/src/utils/fs_cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,27 @@ export const clearFsCache = () => {
fs.emptyDirSync(cacheDir);
};

export const putFsCache = async (key: string, data: any): Promise<void> => {
export const clearFsCacheByContentId = (contentId: string) => {
fs.emptyDirSync(path.join(cacheDir, contentId));
};

export const putFsCache = async (contentId: string, key: string, data: any): Promise<void> => {
fs.ensureDirSync(cacheDir);
const filename = `${key}.json`;
await fs.writeJSON(path.join(cacheDir, filename), data);
await fs.writeJSON(path.join(cacheDir, contentId, filename), data);
};

export const getFsCache = async (key: string): Promise<any> => {
export const getFsCache = async (contentId: string, key: string): Promise<any> => {
fs.ensureDirSync(cacheDir);
const ttl = await getTTL();
const filename = `${key}.json`;
try {
const fileInfo = await fs.stat(path.join(cacheDir, filename));
const fileInfo = await fs.stat(path.join(cacheDir, contentId, filename));
if (fileInfo.mtimeMs + ttl * 1000 < Date.now()) {
await fs.remove(path.join(cacheDir, filename));
await fs.remove(path.join(cacheDir, contentId, filename));
return null;
}
return fs.readJSON(path.join(cacheDir, filename));
return fs.readJSON(path.join(cacheDir, contentId, filename));
} catch (err) {
return null;
}
Expand Down

0 comments on commit 178165b

Please sign in to comment.