Skip to content

Commit

Permalink
feat: redis weak (#426)
Browse files Browse the repository at this point in the history
> manifest 读取场景弱依赖 redis
* 添加 try-catch 防止 redis 请求失败导致读取失败
* 读取完成后异步设置缓存
----
> Redis dependency from manifest with weak scene dependence:

* Adds try-catch to prevent reading failure from redis interruption.
* Asynchronously sets cache after reading is complete.
  • Loading branch information
elrrrrrrr authored Mar 20, 2023
1 parent 5877f71 commit 300f0e4
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 21 deletions.
51 changes: 30 additions & 21 deletions app/port/controller/package/ShowPackageController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,35 @@ export class ShowPackageController extends AbstractController {
const isSync = isSyncWorkerRequest(ctx);
const abbreviatedMetaType = 'application/vnd.npm.install-v1+json';
const isFullManifests = ctx.accepts([ 'json', abbreviatedMetaType ]) !== abbreviatedMetaType;

// handle cache
const cacheEtag = await this.cacheService.getPackageEtag(fullname, isFullManifests);
if (!isSync && cacheEtag) {
let requestEtag = ctx.request.get('if-none-match');
if (requestEtag.startsWith('W/')) {
requestEtag = requestEtag.substring(2);
}
if (requestEtag === cacheEtag) {
// make sure CDN cache header set here
this.setCDNHeaders(ctx);
// match etag, set status 304
ctx.status = 304;
return;
}
// get cache pkg data
const cacheBytes = await this.cacheService.getPackageManifests(fullname, isFullManifests);
if (cacheBytes && cacheBytes.length > 0) {
ctx.set('etag', `W/${cacheEtag}`);
ctx.type = 'json';
this.setCDNHeaders(ctx);
return cacheBytes;
// fallback to db when cache error
try {
const cacheEtag = await this.cacheService.getPackageEtag(fullname, isFullManifests);
if (!isSync && cacheEtag) {
let requestEtag = ctx.request.get('if-none-match');
if (requestEtag.startsWith('W/')) {
requestEtag = requestEtag.substring(2);
}
if (requestEtag === cacheEtag) {
// make sure CDN cache header set here
this.setCDNHeaders(ctx);
// match etag, set status 304
ctx.status = 304;
return;
}
// get cache pkg data
const cacheBytes = await this.cacheService.getPackageManifests(fullname, isFullManifests);
if (cacheBytes && cacheBytes.length > 0) {
ctx.set('etag', `W/${cacheEtag}`);
ctx.type = 'json';
this.setCDNHeaders(ctx);
return cacheBytes;
}
}
} catch (e) {
this.logger.error(e);
this.logger.error('[ShowPackageController.show:error] get cache error, ignore');
}

// handle cache miss
Expand All @@ -78,7 +85,9 @@ export class ShowPackageController extends AbstractController {
// only set cache with normal request
// sync request response with no bug version fixed
if (!isSync) {
await this.cacheService.savePackageEtagAndManifests(fullname, isFullManifests, etag, cacheBytes);
ctx.runInBackground(async () => {
await this.cacheService.savePackageEtagAndManifests(fullname, isFullManifests, etag, cacheBytes);
});
}

// set etag
Expand Down
29 changes: 29 additions & 0 deletions test/port/controller/package/ShowPackageController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,35 @@ describe('test/port/controller/package/ShowPackageController.test.ts', () => {
assert.match(res.body.rev, /^\d+\-\w{24}$/);
});

describe('should fallback when cache error', async () => {
it('should fallback when get etag error', async () => {
app.mockLog();
mock(CacheService.prototype, 'getPackageEtag', async () => {
throw new Error('mock get etag error');
});
await app.httpRequest()
.get(`/${name}`)
.expect(200);

app.expectLog(/ShowPackageController.show:error/);
});

it('should fallback when get getPackageManifests error', async () => {
app.mockLog();
mock(CacheService.prototype, 'getPackageEtag', async () => {
return 'mock-etag';
});
mock(CacheService.prototype, 'getPackageManifests', async () => {
throw new Error('mock get etag error');
});
await app.httpRequest()
.get(`/${name}`)
.expect(200);

app.expectLog(/ShowPackageController.show:error/);
});
});

it('should show one package with full manifests', async () => {
mock(app.config.cnpmcore, 'syncMode', 'all');
const res = await app.httpRequest()
Expand Down

0 comments on commit 300f0e4

Please sign in to comment.