diff --git a/apps/api/src/favoriteSummoner/FavoriteSummonerApiController.ts b/apps/api/src/favoriteSummoner/FavoriteSummonerApiController.ts index 01d4f1e..4035af6 100644 --- a/apps/api/src/favoriteSummoner/FavoriteSummonerApiController.ts +++ b/apps/api/src/favoriteSummoner/FavoriteSummonerApiController.ts @@ -83,7 +83,7 @@ export class FavoriteSummonerApiController { async createFollow( @CurrentUser() userDto: UserReq, @Body() favoriteSummonerDto: FavoriteSummonerReq, - ) { + ): Promise> { try { await this.favoriteSummonerApiService.createFavoriteSummoner( userDto, @@ -138,7 +138,7 @@ export class FavoriteSummonerApiController { async deleteFollow( @CurrentUser() userDto: UserReq, @Body() favoriteSummonerIdDto: FavoriteSummonerIdReq, - ) { + ): Promise> { try { await this.favoriteSummonerApiService.deleteFavoriteSummoner( userDto, @@ -180,7 +180,9 @@ export class FavoriteSummonerApiController { @ApiBearerAuth('Authorization') @UseGuards(JwtAuthGuard) @Get() - async getFollow(@CurrentUser() userDto: UserReq) { + async getFollow( + @CurrentUser() userDto: UserReq, + ): Promise> { try { const data: FavoriteSummonerRes[] = await this.favoriteSummonerApiService.getFavoriteSummoner( diff --git a/apps/push/src/PushAppModule.ts b/apps/push/src/PushAppModule.ts new file mode 100644 index 0000000..6b90115 --- /dev/null +++ b/apps/push/src/PushAppModule.ts @@ -0,0 +1,29 @@ +import { PushApiModule } from './push/PushApiModule'; +import { getBullModule } from '../../../libs/entity/getBullModule'; +import { HealthCheckController } from './health-check/HealthCheckController'; +import { getTypeOrmModule } from '../../../libs/entity/getTypeOrmModule'; +import { LoggingModule } from '@app/common-config/logging/logging.module'; +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TerminusModule } from '@nestjs/terminus'; +import { HttpModule } from '@nestjs/axios'; + +import { AuthConfig, ValidationSchema } from '@app/common-config/config'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + load: [AuthConfig], + isGlobal: true, + validationSchema: ValidationSchema, + }), + getTypeOrmModule(), + getBullModule(), + LoggingModule, + TerminusModule, + HttpModule, + PushApiModule, + ], + controllers: [HealthCheckController], +}) +export class PushAppModule {} diff --git a/apps/push/src/health-check/HealthCheckController.ts b/apps/push/src/health-check/HealthCheckController.ts new file mode 100644 index 0000000..9144230 --- /dev/null +++ b/apps/push/src/health-check/HealthCheckController.ts @@ -0,0 +1,25 @@ +import { Controller, Get } from '@nestjs/common'; +import { + HealthCheckService, + HttpHealthIndicator, + TypeOrmHealthIndicator, + HealthCheck, +} from '@nestjs/terminus'; + +@Controller('health-check') +export class HealthCheckController { + constructor( + private health: HealthCheckService, + // private http: HttpHealthIndicator, + private db: TypeOrmHealthIndicator, + ) {} + + @Get() + @HealthCheck() + check() { + return this.health.check([ + // () => this.http.pingCheck('nestjs-docs', 'https://docs.nestjs.com'), + () => this.db.pingCheck('database'), + ]); + } +} diff --git a/apps/push/src/main.ts b/apps/push/src/main.ts new file mode 100644 index 0000000..c21ee33 --- /dev/null +++ b/apps/push/src/main.ts @@ -0,0 +1,64 @@ +import { NestFactory } from '@nestjs/core'; +import * as winston from 'winston'; +import { + utilities as nestWinstonModuleUtilities, + WinstonModule, +} from 'nest-winston'; +import { PushAppModule } from './PushAppModule'; +import { NestExpressApplication } from '@nestjs/platform-express'; +import { Logger } from '@nestjs/common'; +import { SetNestApp } from '@app/common-config/setNestApp'; + +class Application { + private logger = new Logger(Application.name); + private PORT: string; + private DEV_MODE: boolean; + + constructor(private server: NestExpressApplication) { + this.server = server; + this.PORT = process.env.PUSH_PORT; + this.DEV_MODE = process.env.NODE_ENV === 'production' ? false : true; + } + + async bootstrap() { + SetNestApp(this.server); + await this.server.listen(this.PORT); + } + + startLog() { + if (this.DEV_MODE) { + this.logger.log(`✅ Server on http://localhost:${this.PORT}`); + } else { + this.logger.log(`✅ Server on port ${this.PORT}...`); + } + } +} + +async function bootstrap(): Promise { + const server = await NestFactory.create( + PushAppModule, + { + logger: WinstonModule.createLogger({ + transports: [ + new winston.transports.Console({ + level: process.env.NODE_ENV === 'production' ? 'info' : 'silly', + format: winston.format.combine( + winston.format.timestamp(), + nestWinstonModuleUtilities.format.nestLike('PushApp', { + prettyPrint: true, + }), + ), + }), + ], + }), + }, + ); + + const app = new Application(server); + await app.bootstrap(); + app.startLog(); +} + +bootstrap().catch(error => { + new Logger('init').error(error); +}); diff --git a/apps/push/src/push/PushApiConsumer.ts b/apps/push/src/push/PushApiConsumer.ts new file mode 100644 index 0000000..22af82e --- /dev/null +++ b/apps/push/src/push/PushApiConsumer.ts @@ -0,0 +1,13 @@ +import { Process, Processor } from '@nestjs/bull'; +import { Logger } from '@nestjs/common'; +import { Job } from 'bull'; + +@Processor('testQueue') +export class PushApiConsumer { + private readonly logger = new Logger(PushApiConsumer.name); + + @Process('task') + getMessageQueue(job: Job) { + this.logger.log(`${job.id} 번 작업을 수신했습니다.`); + } +} diff --git a/apps/push/src/push/PushApiController.ts b/apps/push/src/push/PushApiController.ts new file mode 100644 index 0000000..b8db2cf --- /dev/null +++ b/apps/push/src/push/PushApiController.ts @@ -0,0 +1,24 @@ +import { ResponseEntity } from '@app/common-config/response/ResponseEntity'; +import { Body, Controller, Inject, Post } from '@nestjs/common'; +import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; +import { Logger } from 'winston'; +import { PushApiService } from './PushApiService'; + +@Controller() +export class PushApiController { + constructor( + private readonly pushApiService: PushApiService, + @Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: Logger, + ) {} + + @Post('queue') + async addMessage(@Body() data: number): Promise> { + try { + await this.pushApiService.addMessageQueue(data); + return ResponseEntity.OK_WITH('메시지 전송에 성공했습니다.'); + } catch (error) { + this.logger.error(`dto = ${JSON.stringify(data)}`, error); + return ResponseEntity.ERROR_WITH('메시지 전송에 실패했습니다.'); + } + } +} diff --git a/apps/push/src/push/PushApiModule.ts b/apps/push/src/push/PushApiModule.ts new file mode 100644 index 0000000..74b9931 --- /dev/null +++ b/apps/push/src/push/PushApiModule.ts @@ -0,0 +1,18 @@ +import { Module } from '@nestjs/common'; +import { WinstonModule } from 'nest-winston'; +import { getWinstonLogger } from '@app/common-config/getWinstonLogger'; +import { PushApiController } from './PushApiController'; +import { PushApiService } from './PushApiService'; +import { getBullQueue } from '../../../../libs/entity/queue/getBullQueue'; +import { PushApiConsumer } from './PushApiConsumer'; + +@Module({ + imports: [ + WinstonModule.forRoot(getWinstonLogger(process.env.NODE_ENV, 'push')), + getBullQueue(), + ], + controllers: [PushApiController], + providers: [PushApiService, PushApiConsumer], + exports: [getBullQueue()], +}) +export class PushApiModule {} diff --git a/apps/push/src/push/PushApiService.ts b/apps/push/src/push/PushApiService.ts new file mode 100644 index 0000000..109d554 --- /dev/null +++ b/apps/push/src/push/PushApiService.ts @@ -0,0 +1,23 @@ +import { InjectQueue } from '@nestjs/bull'; +import { Injectable } from '@nestjs/common'; +import { Queue, Job } from 'bull'; + +@Injectable() +export class PushApiService { + constructor( + @InjectQueue('testQueue') + private testQueue: Queue, + ) {} + + async addMessageQueue(data: number): Promise { + const job = await this.testQueue.add( + 'task', + { + dataId: data, + }, + { delay: 3000 }, + ); + + return job; + } +} diff --git a/apps/push/tsconfig.app.json b/apps/push/tsconfig.app.json new file mode 100644 index 0000000..d9e1b08 --- /dev/null +++ b/apps/push/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "declaration": false, + "outDir": "../../dist/apps/push" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] +} diff --git a/libs/common-config/src/config/index 2.ts b/libs/common-config/src/config/index 2.ts deleted file mode 100644 index 468ec0f..0000000 --- a/libs/common-config/src/config/index 2.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './authConfig'; -export * from './databaseConfig'; -export * from './validationSchema'; diff --git a/libs/common-config/src/config/index.ts b/libs/common-config/src/config/index.ts index 56ffced..564063e 100644 --- a/libs/common-config/src/config/index.ts +++ b/libs/common-config/src/config/index.ts @@ -1,2 +1,3 @@ export * from './authConfig'; export * from './validationSchema'; +export * from './databaseConfig'; diff --git a/libs/common-config/src/config/validationSchema.ts b/libs/common-config/src/config/validationSchema.ts index f3104ca..f36e37c 100644 --- a/libs/common-config/src/config/validationSchema.ts +++ b/libs/common-config/src/config/validationSchema.ts @@ -2,6 +2,8 @@ import * as Joi from 'joi'; export const ValidationSchema = Joi.object({ PORT: Joi.string().required(), + PUSH_PORT: Joi.string().required(), + DB_HOST: Joi.string().required(), DB_PORT: Joi.string().required(), DB_NAME: Joi.string().required(), @@ -18,5 +20,13 @@ export const ValidationSchema = Joi.object({ TEST_LOGGING: Joi.string().required(), TEST_SYNCHRONIZE: Joi.string().required(), + REDIS_HOST: Joi.string().required(), + REDIS_PORT: Joi.string().required(), + + REDIS_TEST_HOST: Joi.string().required(), + REDIS_TEST_PORT: Joi.string().required(), + + API_KEY: Joi.string().required(), + JWT_SECRET_KEY: Joi.string().required(), }); diff --git a/libs/entity/ormConfig.ts b/libs/entity/config/ormConfig.ts similarity index 100% rename from libs/entity/ormConfig.ts rename to libs/entity/config/ormConfig.ts diff --git a/libs/entity/config/redisConfig.ts b/libs/entity/config/redisConfig.ts new file mode 100644 index 0000000..aca3ea3 --- /dev/null +++ b/libs/entity/config/redisConfig.ts @@ -0,0 +1,15 @@ +import * as dotenv from 'dotenv'; +import { QueueOptions } from 'bull'; + +dotenv.config(); + +const [host, port] = + process.env.NODE_ENV === 'production' + ? [process.env.REDIS_HOST, process.env.REDIS_PORT] + : [process.env.REDIS_TEST_HOST, process.env.REDIS_TEST_PORT]; + +const RedisConfig: QueueOptions = { + redis: { host, port: Number(port) }, +}; + +export = RedisConfig; diff --git a/libs/entity/seedConfig.ts b/libs/entity/config/seedConfig.ts similarity index 100% rename from libs/entity/seedConfig.ts rename to libs/entity/config/seedConfig.ts diff --git a/libs/entity/getBullModule.ts b/libs/entity/getBullModule.ts new file mode 100644 index 0000000..e304191 --- /dev/null +++ b/libs/entity/getBullModule.ts @@ -0,0 +1,6 @@ +import { BullModule } from '@nestjs/bull'; +import * as RedisConfig from './config/redisConfig'; + +export function getBullModule() { + return BullModule.forRoot(RedisConfig); +} diff --git a/libs/entity/getTypeOrmModule.ts b/libs/entity/getTypeOrmModule.ts index 4ab84ce..8f97d48 100644 --- a/libs/entity/getTypeOrmModule.ts +++ b/libs/entity/getTypeOrmModule.ts @@ -1,5 +1,5 @@ import { TypeOrmModule } from '@nestjs/typeorm'; -import * as ormConfig from './ormConfig'; +import * as ormConfig from './config/ormConfig'; export function getTypeOrmModule() { return TypeOrmModule.forRoot(ormConfig); diff --git a/libs/entity/queue/getBullQueue.ts b/libs/entity/queue/getBullQueue.ts new file mode 100644 index 0000000..96a7cd2 --- /dev/null +++ b/libs/entity/queue/getBullQueue.ts @@ -0,0 +1,7 @@ +import { BullModule } from '@nestjs/bull'; + +export function getBullQueue() { + return BullModule.registerQueue({ + name: 'testQueue', + }); +} diff --git a/nest-cli.json b/nest-cli.json index a49b95c..a3d0546 100644 --- a/nest-cli.json +++ b/nest-cli.json @@ -1,6 +1,7 @@ { "collection": "@nestjs/schematics", - "sourceRoot": "apps/api/src", + "sourceRoot": "apps/push/src", + "monorepo": true, "projects": { "entity": { "type": "library", @@ -20,6 +21,15 @@ "tsConfigPath": "apps/api/tsconfig.app.json" } }, + "push": { + "type": "application", + "root": "apps/push", + "entryFile": "main", + "sourceRoot": "apps/push/src", + "compilerOptions": { + "tsConfigPath": "apps/push/tsconfig.app.json" + } + }, "common-config": { "type": "library", "root": "libs/common-config", diff --git a/package-lock.json b/package-lock.json index 60c0ce4..8da5969 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "UNLICENSED", "dependencies": { "@nestjs/axios": "^0.0.5", + "@nestjs/bull": "^0.5.4", "@nestjs/common": "^8.0.0", "@nestjs/config": "^1.1.6", "@nestjs/core": "^8.0.0", @@ -20,6 +21,7 @@ "@nestjs/terminus": "^8.0.4", "@nestjs/typeorm": "^8.0.3", "axios": "^0.26.1", + "bull": "^4.8.1", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "express-basic-auth": "^1.2.1", @@ -44,6 +46,7 @@ "@nestjs/cli": "^8.0.0", "@nestjs/schematics": "^8.0.0", "@nestjs/testing": "^8.0.0", + "@types/bull": "^3.15.8", "@types/express": "^4.17.13", "@types/jest": "27.0.2", "@types/node": "^16.0.0", @@ -1253,6 +1256,32 @@ "follow-redirects": "^1.14.7" } }, + "node_modules/@nestjs/bull": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@nestjs/bull/-/bull-0.5.4.tgz", + "integrity": "sha512-0w9E+Qvcyqfjwis6qrLIXjAUZcXZW1L4Yv0ytGMIuaZCrawx5NX0ytBRpRJTcvzIf8TEvNmNydt6fTn4iA/hiQ==", + "dependencies": { + "@nestjs/bull-shared": "^0.0.4", + "tslib": "2.3.1" + }, + "peerDependencies": { + "@nestjs/common": "^6.10.11 || ^7.0.0 || ^8.0.0", + "@nestjs/core": "^6.10.11 || ^7.0.0 || ^8.0.0", + "bull": "^3.3 || ^4.0.0" + } + }, + "node_modules/@nestjs/bull-shared": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@nestjs/bull-shared/-/bull-shared-0.0.4.tgz", + "integrity": "sha512-w+J04AffCMNiB48rIR5P61MvbgkIlq0Tvk4hE4Up+g20H8rhfnxbOyd9bWyLHtf8QhziK6JyViyGFLZ3meBRIA==", + "dependencies": { + "tslib": "2.3.1" + }, + "peerDependencies": { + "@nestjs/common": "^6.10.11 || ^7.0.0 || ^8.0.0", + "@nestjs/core": "^6.10.11 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/@nestjs/cli": { "version": "8.2.0", "dev": true, @@ -1775,6 +1804,16 @@ "@types/node": "*" } }, + "node_modules/@types/bull": { + "version": "3.15.8", + "resolved": "https://registry.npmjs.org/@types/bull/-/bull-3.15.8.tgz", + "integrity": "sha512-8DbSPMSsZH5PWPnGEkAZLYgJEH4ghHJNKF7LB6Wr5R0/v6g+Vs+JoaA7kcvLtHE936xg2WpFPkaoaJgExOmKDw==", + "dev": true, + "dependencies": { + "@types/ioredis": "*", + "@types/redis": "^2.8.0" + } + }, "node_modules/@types/connect": { "version": "3.4.35", "dev": true, @@ -1840,6 +1879,15 @@ "@types/node": "*" } }, + "node_modules/@types/ioredis": { + "version": "4.28.10", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", + "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "dev": true, @@ -1953,6 +2001,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/redis": { + "version": "2.8.32", + "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.32.tgz", + "integrity": "sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/serve-static": { "version": "1.13.10", "dev": true, @@ -2887,6 +2944,25 @@ "node": ">=4" } }, + "node_modules/bull": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/bull/-/bull-4.8.1.tgz", + "integrity": "sha512-ojH5AfOchKQsQwwE+thViS1pMpvREGC+Ov1+3HXsQqn5Q27ZSGkgMriMqc6c9J9rvQ/+D732pZE+TN1+2LRWVg==", + "dependencies": { + "cron-parser": "^4.2.1", + "debuglog": "^1.0.0", + "get-port": "^5.1.1", + "ioredis": "^4.28.5", + "lodash": "^4.17.21", + "msgpackr": "^1.5.2", + "p-timeout": "^3.2.0", + "semver": "^7.3.2", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=10.1" + } + }, "node_modules/busboy": { "version": "0.2.14", "dependencies": { @@ -3131,6 +3207,14 @@ "node": ">=0.8" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/co": { "version": "4.6.0", "dev": true, @@ -3346,6 +3430,17 @@ "dev": true, "license": "MIT" }, + "node_modules/cron-parser": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.3.0.tgz", + "integrity": "sha512-mK6qJ6k9Kn0/U7Cv6LKQnReUW3GqAW4exgwmHJGb3tPgcy0LrS+PeqxPPiwL8uW/4IJsMsCZrCc4vf1nnXMjzA==", + "dependencies": { + "luxon": "^1.28.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "dev": true, @@ -3416,6 +3511,14 @@ } } }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "engines": { + "node": "*" + } + }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -3462,6 +3565,14 @@ "node": ">=0.4.0" } }, + "node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "1.1.2", "license": "MIT", @@ -4737,6 +4848,17 @@ "node": ">=8.0.0" } }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "6.0.1", "dev": true, @@ -5137,6 +5259,31 @@ "node": ">= 0.10" } }, + "node_modules/ioredis": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz", + "integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==", + "dependencies": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "license": "MIT", @@ -6407,10 +6554,25 @@ "version": "4.17.21", "license": "MIT" }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, "node_modules/lodash.includes": { "version": "4.3.0", "license": "MIT" }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, "node_modules/lodash.isboolean": { "version": "3.0.3", "license": "MIT" @@ -6488,7 +6650,6 @@ }, "node_modules/lru-cache": { "version": "6.0.0", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -6504,6 +6665,14 @@ "es5-ext": "~0.10.2" } }, + "node_modules/luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", + "engines": { + "node": "*" + } + }, "node_modules/macos-release": { "version": "2.5.0", "dev": true, @@ -6697,6 +6866,25 @@ "version": "2.1.2", "license": "MIT" }, + "node_modules/msgpackr": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.5.5.tgz", + "integrity": "sha512-JG0V47xRIQ9pyUnx6Hb4+3TrQoia2nA3UIdmyTldhxaxtKFkekkKpUW/N6fwHwod9o4BGuJGtouxOk+yCP5PEA==", + "optionalDependencies": { + "msgpackr-extract": "^1.0.14" + } + }, + "node_modules/msgpackr-extract": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-1.0.16.tgz", + "integrity": "sha512-fxdRfQUxPrL/TizyfYfMn09dK58e+d65bRD/fcaVH4052vj30QOzzqxcQIS7B0NsqlypEQ/6Du3QmP2DhWFfCA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "nan": "^2.14.2", + "node-gyp-build": "^4.2.3" + } + }, "node_modules/multer": { "version": "1.4.4", "license": "MIT", @@ -6739,6 +6927,12 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "optional": true + }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, @@ -6815,6 +7009,17 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-int64": { "version": "0.4.0", "dev": true, @@ -6989,6 +7194,14 @@ "node": ">=0.10.0" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "2.3.0", "license": "MIT", @@ -7012,6 +7225,25 @@ "node": ">=8" } }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-try": { "version": "2.2.0", "license": "MIT", @@ -7502,6 +7734,30 @@ "node": ">= 0.10" } }, + "node_modules/redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/reflect-metadata": { "version": "0.1.13", "license": "Apache-2.0" @@ -7744,7 +8000,6 @@ }, "node_modules/semver": { "version": "7.3.5", - "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -7999,6 +8254,11 @@ "node": ">=8" } }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "node_modules/statuses": { "version": "1.5.0", "license": "MIT", @@ -9772,7 +10032,6 @@ }, "node_modules/yallist": { "version": "4.0.0", - "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -10634,6 +10893,23 @@ } } }, + "@nestjs/bull": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@nestjs/bull/-/bull-0.5.4.tgz", + "integrity": "sha512-0w9E+Qvcyqfjwis6qrLIXjAUZcXZW1L4Yv0ytGMIuaZCrawx5NX0ytBRpRJTcvzIf8TEvNmNydt6fTn4iA/hiQ==", + "requires": { + "@nestjs/bull-shared": "^0.0.4", + "tslib": "2.3.1" + } + }, + "@nestjs/bull-shared": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@nestjs/bull-shared/-/bull-shared-0.0.4.tgz", + "integrity": "sha512-w+J04AffCMNiB48rIR5P61MvbgkIlq0Tvk4hE4Up+g20H8rhfnxbOyd9bWyLHtf8QhziK6JyViyGFLZ3meBRIA==", + "requires": { + "tslib": "2.3.1" + } + }, "@nestjs/cli": { "version": "8.2.0", "dev": true, @@ -10939,6 +11215,16 @@ "@types/node": "*" } }, + "@types/bull": { + "version": "3.15.8", + "resolved": "https://registry.npmjs.org/@types/bull/-/bull-3.15.8.tgz", + "integrity": "sha512-8DbSPMSsZH5PWPnGEkAZLYgJEH4ghHJNKF7LB6Wr5R0/v6g+Vs+JoaA7kcvLtHE936xg2WpFPkaoaJgExOmKDw==", + "dev": true, + "requires": { + "@types/ioredis": "*", + "@types/redis": "^2.8.0" + } + }, "@types/connect": { "version": "3.4.35", "dev": true, @@ -10996,6 +11282,15 @@ "@types/node": "*" } }, + "@types/ioredis": { + "version": "4.28.10", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", + "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.4", "dev": true @@ -11092,6 +11387,15 @@ "version": "1.2.4", "dev": true }, + "@types/redis": { + "version": "2.8.32", + "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.32.tgz", + "integrity": "sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/serve-static": { "version": "1.13.10", "dev": true, @@ -11687,6 +11991,22 @@ "buffer-writer": { "version": "2.0.0" }, + "bull": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/bull/-/bull-4.8.1.tgz", + "integrity": "sha512-ojH5AfOchKQsQwwE+thViS1pMpvREGC+Ov1+3HXsQqn5Q27ZSGkgMriMqc6c9J9rvQ/+D732pZE+TN1+2LRWVg==", + "requires": { + "cron-parser": "^4.2.1", + "debuglog": "^1.0.0", + "get-port": "^5.1.1", + "ioredis": "^4.28.5", + "lodash": "^4.17.21", + "msgpackr": "^1.5.2", + "p-timeout": "^3.2.0", + "semver": "^7.3.2", + "uuid": "^8.3.0" + } + }, "busboy": { "version": "0.2.14", "requires": { @@ -11836,6 +12156,11 @@ "clone": { "version": "1.0.4" }, + "cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + }, "co": { "version": "4.6.0", "dev": true @@ -11992,6 +12317,14 @@ "version": "1.1.1", "dev": true }, + "cron-parser": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.3.0.tgz", + "integrity": "sha512-mK6qJ6k9Kn0/U7Cv6LKQnReUW3GqAW4exgwmHJGb3tPgcy0LrS+PeqxPPiwL8uW/4IJsMsCZrCc4vf1nnXMjzA==", + "requires": { + "luxon": "^1.28.0" + } + }, "cross-spawn": { "version": "7.0.3", "dev": true, @@ -12040,6 +12373,11 @@ "ms": "2.1.2" } }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -12071,6 +12409,11 @@ "version": "1.0.0", "dev": true }, + "denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" + }, "depd": { "version": "1.1.2" }, @@ -12913,6 +13256,11 @@ "version": "0.1.0", "dev": true }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + }, "get-stream": { "version": "6.0.1", "dev": true @@ -13157,6 +13505,24 @@ "version": "1.4.0", "dev": true }, + "ioredis": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz", + "integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==", + "requires": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + } + }, "ipaddr.js": { "version": "1.9.1" }, @@ -14023,9 +14389,24 @@ "lodash": { "version": "4.17.21" }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, "lodash.includes": { "version": "4.3.0" }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, "lodash.isboolean": { "version": "3.0.3" }, @@ -14082,7 +14463,6 @@ }, "lru-cache": { "version": "6.0.0", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -14093,6 +14473,11 @@ "es5-ext": "~0.10.2" } }, + "luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" + }, "macos-release": { "version": "2.5.0", "dev": true @@ -14215,6 +14600,24 @@ "ms": { "version": "2.1.2" }, + "msgpackr": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.5.5.tgz", + "integrity": "sha512-JG0V47xRIQ9pyUnx6Hb4+3TrQoia2nA3UIdmyTldhxaxtKFkekkKpUW/N6fwHwod9o4BGuJGtouxOk+yCP5PEA==", + "requires": { + "msgpackr-extract": "^1.0.14" + } + }, + "msgpackr-extract": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-1.0.16.tgz", + "integrity": "sha512-fxdRfQUxPrL/TizyfYfMn09dK58e+d65bRD/fcaVH4052vj30QOzzqxcQIS7B0NsqlypEQ/6Du3QmP2DhWFfCA==", + "optional": true, + "requires": { + "nan": "^2.14.2", + "node-gyp-build": "^4.2.3" + } + }, "multer": { "version": "1.4.4", "requires": { @@ -14243,6 +14646,12 @@ "thenify-all": "^1.0.0" } }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "optional": true + }, "natural-compare": { "version": "1.4.0", "dev": true @@ -14294,6 +14703,12 @@ } } }, + "node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "optional": true + }, "node-int64": { "version": "0.4.0", "dev": true @@ -14404,6 +14819,11 @@ "version": "1.0.2", "dev": true }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, "p-limit": { "version": "2.3.0", "requires": { @@ -14416,6 +14836,19 @@ "p-limit": "^2.2.0" } }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0" }, @@ -14702,6 +15135,24 @@ "resolve": "^1.1.6" } }, + "redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "^1.0.0" + } + }, "reflect-metadata": { "version": "0.1.13" }, @@ -14844,7 +15295,6 @@ }, "semver": { "version": "7.3.5", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -15023,6 +15473,11 @@ } } }, + "standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "statuses": { "version": "1.5.0" }, @@ -16081,8 +16536,7 @@ "version": "5.0.8" }, "yallist": { - "version": "4.0.0", - "dev": true + "version": "4.0.0" }, "yaml": { "version": "1.10.2", diff --git a/package.json b/package.json index a91c926..a01d05b 100644 --- a/package.json +++ b/package.json @@ -25,11 +25,12 @@ "typeorm:migrate": "npm run typeorm migration:generate -- -n", "typeorm:run": "npm run typeorm migration:run", "typeorm:revert": "npm run typeorm migration:revert", - "seed:run": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed -n libs/entity/seedConfig.ts", - "seed:user": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed -n libs/entity/seedConfig.ts --seed CreateUser" + "seed:run": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed -n libs/entity/config/seedConfig.ts", + "seed:user": "ts-node ./node_modules/typeorm-seeding/dist/cli.js seed -n libs/entity/config/seedConfig.ts --seed CreateUser" }, "dependencies": { "@nestjs/axios": "^0.0.5", + "@nestjs/bull": "^0.5.4", "@nestjs/common": "^8.0.0", "@nestjs/config": "^1.1.6", "@nestjs/core": "^8.0.0", @@ -40,6 +41,7 @@ "@nestjs/terminus": "^8.0.4", "@nestjs/typeorm": "^8.0.3", "axios": "^0.26.1", + "bull": "^4.8.1", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "express-basic-auth": "^1.2.1", @@ -64,6 +66,7 @@ "@nestjs/cli": "^8.0.0", "@nestjs/schematics": "^8.0.0", "@nestjs/testing": "^8.0.0", + "@types/bull": "^3.15.8", "@types/express": "^4.17.13", "@types/jest": "27.0.2", "@types/node": "^16.0.0",