Files
ranking/src/services/ranking.service.ts
2025-12-16 20:06:49 +09:00

80 lines
2.5 KiB
TypeScript

import type { RealEstateArticle } from "../generated/prisma";
import type { NaverRealEstate } from "./naver.service";
import { prisma } from "../../lib/prisma";
import pLimit from "p-limit";
export class RankingService {
private naver: NaverRealEstate;
constructor(naver: NaverRealEstate) {
this.naver = naver;
}
async updateRanking(articles: RealEstateArticle[], checkDate: Date) {
const { token, cookie } = await this.naver.getRankingToken();
for (let i = 0; i < articles.length; i += 20) {
const batch = articles.slice(i, i + 20);
console.log(`🚀 ${i + 1} ~ ${i + batch.length}번 매물 처리 시작`);
const tasks = batch.map(async (article) => {
try {
// cortarNo, lgeo 확인
if (!article.cortarNo || !article.lgeo) {
const { cortarNo, lgeo } = await this.updateCortarNoAndLgeo(
article
);
article.cortarNo = cortarNo;
article.lgeo = lgeo;
}
// 랭킹 조회
const ranking = await this.naver.getRanking(article, token, cookie);
// DB 업데이트
await prisma.realEstateArticle.update({
where: { id: article.id },
data: {
ranking,
rankCheckDate: checkDate.toISOString(),
},
});
console.log(`${article.articleNumber} - 랭킹 완료 : ${ranking}`);
} catch (err) {
console.error(`❌ 오류: ${article.articleNumber}`, err);
}
});
// **이 10개(또는 마지막 batch)가 모두 끝날 때까지 기다림**
await Promise.allSettled(tasks);
// 다음 배치가 남아있다면 딜레이
if (i + 20 < articles.length) {
console.log(`⏸ 10개 처리 완료 → 10초 휴식`);
await Bun.sleep(5000);
}
}
console.log("🎉 전체 랭킹 업데이트 완료!");
await Bun.sleep(100);
}
async updateCortarNoAndLgeo(article: RealEstateArticle): Promise<{
cortarNo: string | null;
lgeo: string | null;
}> {
try {
const { cortarNo, lgeo } = await this.naver.getCortarNoAndLgeo(article);
await prisma.realEstateArticle.update({
where: { id: article.id },
data: { cortarNo: cortarNo ?? null, lgeo: lgeo ?? null },
});
return { cortarNo: cortarNo ?? null, lgeo: lgeo ?? null };
} catch (error) {
console.error(`❌ 오류 발생:`, error);
return { cortarNo: null, lgeo: null };
}
}
}