๋งํฌ ๋๋ผํผ๋ ์ฌ์ฉ์์๊ฒ ์๋ง์ ๋งํฌ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ, ์ญ์ ๋ ๋ ๊ณ ๋ฏผ์ด์์ต๋๋ค.
โ์ค์๋ก ์ญ์ ํ ๋งํฌ๋ ๋ณต๊ตฌํ ์ ์์๊น?โ, โ์ง์ ์ง๋ง ๋ค์ ๋ณด๊ณ ์ถ์ด์ง๋ฉด?โ
๊ทธ๋์ ๋ง๋ค์์ต๋๋ค. ํด์งํต ์์คํ
.
๋ณด๊ด ์ค์ธ ๋งํฌ๋ ํด๋๋ฅผ ์ญ์ ํ๋ฉด ๋ฐ๋ก DB์์ ์ฌ๋ผ์ง๋ ๊ฒ ์๋๋ผ, ํด์งํต์ผ๋ก ์ด๋
๋ฉ๋๋ค.
์ด์ ๋งํฌ ๋๋ผํผ์ ์ญ์ ๋ ๊ณง โ30์ผ ๋์์ ์ ์โ๋ฅผ ์๋ฏธํฉ๋๋ค.
// ๋งํฌ ์ญ์ ์ ์ฒ๋ฆฌ
PATCH /api/links/:id/trash
// ํด๋ ์ญ์ ์ ์ฒ๋ฆฌ
PATCH /api/folders/:id/trash
// ์์ ์ฝ๋ (NestJS)
await this.linkRepository.update(id, {{
isTrashed: true,
trashedAt: new Date(),
}});
isTrashed = true
์ trashedAt = now
๋ง ์ค์ ํ๋ฉด ๋!isTrashed
์ํ์ ๋ฐ๋ผ ํด์งํต ์ ์ฉ ๋ทฐ๋ก ๋ถ๋ฆฌ๋ฉ๋๋ค.์ญ์ ํ ๋งํฌ๋ฅผ 30์ผ ์ด์ ๋ฐฉ์นํ๋ฉด?
๐ softDelete๋ก ์ค์ ์ญ์ ์ฒ๋ฆฌ๊ฐ ์๋์ผ๋ก ๋ฉ๋๋ค.
Cron์ ํน์ ์๊ฐ์ ํน์ ์์
์ ๋ฐ๋ณต ์คํํ ์ ์๋๋ก ํด์ฃผ๋ ์ค์ผ์ค๋ง ์์คํ
์
๋๋ค.
๋ฆฌ๋
์ค ๊ธฐ๋ฐ ์๋ฒ์์ ๋ง์ด ์ฌ์ฉ๋๋ฉฐ, NestJS์์๋ @nestjs/schedule
๋ชจ๋๋ก ๊ฐํธํ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
ํํ์ | ์ค๋ช |
---|---|
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT) | ๋งค์ผ ์์ ์ ์คํ |
@Cron('0 0 * * *') | ๋งค์ผ ์์ ์ ์คํ (๋์ผ ์๋ฏธ) |
@Cron('0 */6 * * *') | 6์๊ฐ๋ง๋ค ์คํ |
@Cron(CronExpression.EVERY_HOUR) | ๋งค ์ ์์ ์คํ |
NestJS์์ Cron ์์ ์ ๋ง๋ค๊ธฐ ์ํด์๋ ๋ค์ 3๊ฐ์ง๋ง ๊ธฐ์ตํ์ธ์:
@nestjs/schedule
์ค์น ๋ฐ ScheduleModule.forRoot()
๋ฑ๋ก@Cron(...)
๋ฐ์ฝ๋ ์ดํฐ ์ฌ์ฉ์ ๋ฆฌ ์์ , ํต๊ณ ์ง๊ณ, ์๋ ์๋ฆผ ๋ฑ ๋ค์ํ ๋ฐฑ์๋ ์๋ํ ์์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
npm install @nestjs/schedule
// trash-cleanup.service.ts
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
async handleCron() {{
const deadline = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
const oldLinks = await this.linkRepo.find({{
where: {{
isTrashed: true,
trashedAt: LessThan(deadline),
deletedAt: null,
}},
}});
await this.linkRepo.softRemove(oldLinks);
}}
softRemove
๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ ๋ฌผ๋ฆฌ ์ญ์ ๋์ง ์๊ณ , deletedAt
๋ง ๊ธฐ๋ก๋ฉ๋๋ค.์ฐ๋ฆฌ๋ ๋งํฌ๋ฅผ ์ ์ฅํ ๋ โ๋์ค์ ๊ผญ ์ฝ์ ๊ฑฐ์ผโ๋ผ๊ณ ์๊ฐํฉ๋๋ค.
ํ์ง๋ง ํ์ค์... ์ ์ฝ๊ณ ๋ฐฉ์น๋ ๋งํฌ์ ๋ฌด๋ค.
๊ทธ๋์ ์ ์ํฉ๋๋ค.
โ3์ผ ๋์ ์ฝ์ง ์์ ๋งํฌ๋ ์๋ ์ ๋ฆฌํ์.โ
์ด ๊ธฐ๋ฅ์ ๋จ์ํ ์ญ์ ๋ฅผ ์ํ ๊ฒ์ด ์๋๋๋ค.
์ฌ์ฉ์์๊ฒ ๋ค์ ํ ๋ฒ ๋ฌป๋ ๊ฑฐ์ฃ :
โ์ด ๋งํฌ, ์ง์ง ์ ์ฝ์ผ์ค ๊ฑด๊ฐ์?โ
๐ฌ โ์ฝ์ง ์์ ๋งํฌ 5๊ฐ๊ฐ ์์ด์. ํด์งํต์ผ๋ก ์ ๋ฆฌํ ๊น์?โ
// 3์ผ ์ด์ ์ฝ์ง ์์ ๋งํฌ โ ํด์งํต์ผ๋ก ์ด๋
const deadline = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
const unreadLinks = await this.linkRepo.find({{
where: {{
isRead: false,
createdAt: LessThan(deadline),
isTrashed: false,
userId: currentUser.id,
userSetting: {{ autoTrashUnreadLinks: true }},
}},
});
for (const link of unreadLinks) {{
link.isTrashed = true;
link.trashedAt = new Date();
await this.linkRepo.save(link);
}}
๐ ์ข์์๋ฅผ ๋๋ฌ์ฃผ์๊ฑฐ๋
๐ ๋๊ธ๋ก ์๊ฒฌ์ ๋จ๊ฒจ์ฃผ์ธ์!
์ฌ๋ฌ๋ถ์ ํผ๋๋ฐฑ์ผ๋ก ๊ธฐ๋ฅ์ ์กฐ์ ํ๊ณ , ๋ ๋์ UX๋ฅผ ๋ง๋ค์ด๊ฐ๊ฒ ์ต๋๋ค.
๋งํฌ ๋๋ผํผ๋ ๋จ์ํ ์ ์ฅ ํด์ด ์๋๋๋ค.
์ ๋ฆฌํ๊ณ , ์์ ํ๊ณ , ๋ค์ ๊บผ๋ด๋ณด๊ฒ ๋ง๋๋ ๋งํฌ ๊ด๋ฆฌ ๋๊ตฌ์
๋๋ค.
โข ๐ ๋งํฌ ์ญ์ , ํด๋ ์์ฑ/์์ ๋ฑ์ ๋๊ด์ ์ผ๋ก ์ฒ๋ฆฌ
โข ๐ง ๋งํฌ ์๋ฏธ๋ฅผ ๊ธฐ์ตํ๊ฒ ๋ง๋๋ ๋ฉ๋ชจ ๊ธฐ๋ฅ
โข ๐ ํด๋๋ฅผ ์น๊ตฌ์๊ฒ ๊ณต์ ๊ฐ๋ฅ
โข โก OG ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์๋ ๋ถ๋ฌ์ค๊ธฐ
๐ ๐ ๋งํฌ ๋๋ผํผ ๋ฒ ํ ์ฒดํํ๋ฌ ๊ฐ๊ธฐ
์นด์นด์คํก ์ฑ๋์ ์ถ๊ฐํ์๋ฉด
์
๋ฐ์ดํธ ์์, ๊ธฐ๋ฅ ๊ฟํ, ์ด๋ฒคํธ ๋ฑ์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ณด์ค ์ ์์ต๋๋ค.