Commit 0a8ef507 authored by nanahira's avatar nanahira

add lock to image resize

parent ce97de60
Pipeline #14449 passed with stages
in 5 minutes and 7 seconds
This diff is collapsed.
......@@ -21,6 +21,7 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs-modules/ioredis": "^1.0.1",
"@nestjs/axios": "^0.0.4",
"@nestjs/common": "^8.0.0",
"@nestjs/config": "^1.1.6",
......@@ -31,9 +32,11 @@
"@xzeldon/imagemagick-native": "^1.9.5",
"class-transformer": "^0.4.0",
"class-validator": "^0.13.2",
"ioredis": "^4.28.5",
"lodash": "^4.17.21",
"pg": "^8.7.1",
"pg-native": "^3.0.0",
"redlock": "^5.0.0-beta.2",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
......
......@@ -7,6 +7,8 @@ import { HttpModule } from '@nestjs/axios';
import { AvatarApiService } from './avatar-api/avatar-api.service';
import { ImageService } from './image/image.service';
import { Avatar } from './entities/Avatar.entity';
import { LockService } from './lock/lock.service';
import { RedisModule } from '@nestjs-modules/ioredis';
@Module({
imports: [
......@@ -31,8 +33,16 @@ import { Avatar } from './entities/Avatar.entity';
};
},
}),
RedisModule.forRootAsync({
inject: [ConfigService],
useFactory: async (config: ConfigService) => ({
config: {
url: config.get('REDIS_URL'),
},
}),
}),
],
controllers: [AppController],
providers: [AppService, AvatarApiService, ImageService],
providers: [AppService, AvatarApiService, ImageService, LockService],
})
export class AppModule {}
......@@ -4,6 +4,7 @@ import { Injectable, ConsoleLogger } from '@nestjs/common';
import { ImageService } from './image/image.service';
import { AvatarApiService } from './avatar-api/avatar-api.service';
import { Avatar } from './entities/Avatar.entity';
import { LockService } from './lock/lock.service';
@Injectable()
export class AppService extends ConsoleLogger {
......@@ -12,6 +13,7 @@ export class AppService extends ConsoleLogger {
private db: Connection,
private image: ImageService,
private avatarApi: AvatarApiService,
private lockService: LockService,
) {
super('app');
}
......@@ -37,30 +39,39 @@ export class AppService extends ConsoleLogger {
return existingAvatar.toBuffer();
}
this.log(`Resizing ${url} to ${size}`);
let originalAvatarBuffer: Buffer;
const originalAvatar = await this.db.getRepository(Avatar).findOne({
where: {
url,
size: 0,
return this.lockService.using(
[`avatar_${url}_${size}`],
10000,
async () => {
let originalAvatarBuffer: Buffer;
const originalAvatar = await this.db.getRepository(Avatar).findOne({
where: {
url,
size: 0,
},
select: ['content'],
});
if (originalAvatar) {
originalAvatarBuffer = originalAvatar.toBuffer();
} else {
originalAvatarBuffer = await this.avatarApi.downloadAvatar(url);
try {
await this.saveAvatar(url, 0, originalAvatarBuffer);
} catch (e) {
this.error(`Fail to save original avatar: ${e.message}`);
}
}
const avatarBuffer = await this.image.resize(
originalAvatarBuffer,
size,
);
try {
await this.saveAvatar(url, size, avatarBuffer);
} catch (e) {
this.error(`Fail to save avatar: ${e.message}`);
}
return avatarBuffer;
},
select: ['content'],
});
if (originalAvatar) {
originalAvatarBuffer = originalAvatar.toBuffer();
} else {
originalAvatarBuffer = await this.avatarApi.downloadAvatar(url);
try {
await this.saveAvatar(url, 0, originalAvatarBuffer);
} catch (e) {
this.error(`Fail to save original avatar: ${e.message}`);
}
}
const avatarBuffer = await this.image.resize(originalAvatarBuffer, size);
try {
await this.saveAvatar(url, size, avatarBuffer);
} catch (e) {
this.error(`Fail to save avatar: ${e.message}`);
}
return avatarBuffer;
);
}
}
import { Test, TestingModule } from '@nestjs/testing';
import { LockService } from './lock.service';
describe('LockService', () => {
let service: LockService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [LockService],
}).compile();
service = module.get<LockService>(LockService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import { InjectRedis, Redis } from '@nestjs-modules/ioredis';
import { Injectable } from '@nestjs/common';
import Redlock from 'redlock';
@Injectable()
export class LockService extends Redlock {
constructor(@InjectRedis() private readonly redis: Redis) {
super([redis]);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment