80 lines
2.5 KiB
TypeScript
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 };
|
|
}
|
|
}
|
|
}
|