115 lines
3.6 KiB
JavaScript
115 lines
3.6 KiB
JavaScript
const { Worker } = require("bullmq")
|
||
const Redis = require("ioredis")
|
||
const { getRedisConnectionOptions } = require("../services/redis/connection")
|
||
|
||
const TRENDING_DEAL_TTL_SECONDS = 12 * 60 * 60
|
||
const TRENDING_DEAL_LIMIT = 1000
|
||
const TRENDING_DEAL_WINDOW_DAYS = 2 // Test için burayı 30 yapıp deneyebilirsin
|
||
|
||
function createRedisClient() {
|
||
return new Redis(getRedisConnectionOptions())
|
||
}
|
||
function parseSearchResults(results = []) {
|
||
const ids = [];
|
||
|
||
// i=1'den başlıyoruz (results[0] toplam sayıdır), ikişer ikişer atlıyoruz
|
||
for (let i = 1; i < results.length; i += 2) {
|
||
const key = results[i]; // Örn: "deals:cache:20"
|
||
const value = results[i + 1]; // Örn: ["$", "[{\"id\":20,...}]"]
|
||
|
||
try {
|
||
// Dialect 3 formatında JSON her zaman bir array string'i olarak gelir: [0] = "$", [1] = "[{...}]"
|
||
// JSON.parse(value[1])[0] diyerek direkt objeye ulaşıyoruz.
|
||
const [deal] = JSON.parse(value[1]);
|
||
ids.push(Number(deal.id));
|
||
} catch {
|
||
// Eğer JSON'da bir sorun olursa, ID'yi key'den (deals:cache:20) güvenli bir şekilde çek
|
||
const idFromKey = key.split(":")[2];
|
||
if (idFromKey) ids.push(Number(idFromKey));
|
||
}
|
||
}
|
||
return ids;
|
||
}
|
||
|
||
async function buildTrendingDealList() {
|
||
const redis = createRedisClient()
|
||
|
||
try {
|
||
const now = Date.now()
|
||
// windowMs'i tam sayıya yuvarlayalım
|
||
const windowMs = Math.floor(Number(TRENDING_DEAL_WINDOW_DAYS) * 24 * 60 * 60 * 1000)
|
||
const cutoffMs = now - windowMs
|
||
|
||
// DEBUG: Zaman aralığını kontrol edelim
|
||
console.log(`🕒 Şu an: ${new Date(now).toISOString()}`)
|
||
console.log(`🕒 Cutoff (Eşik): ${new Date(cutoffMs).toISOString()}`)
|
||
|
||
/**
|
||
* SORGUNUN ANALİZİ:
|
||
* 1. @status:{ACTIVE} -> Veritabanında 'ACTIVE' (BÜYÜK HARF) olduğundan emin ol.
|
||
* 2. @createdAtTs:[${cutoffMs} +inf] -> Sayısal aralık.
|
||
*/
|
||
const query = `@status:{ACTIVE} @createdAtTs:[${cutoffMs} +inf]`
|
||
|
||
console.log(`🔍 Redis Query: FT.SEARCH idx:deals "${query}" SORTBY score DESC DIALECT 3`)
|
||
|
||
const results = await redis.call(
|
||
"FT.SEARCH",
|
||
"idx:deals",
|
||
query,
|
||
"SORTBY", "score", "DESC",
|
||
"LIMIT", "0", String(TRENDING_DEAL_LIMIT),
|
||
"DIALECT", "3",
|
||
"RETURN", "1", "$"
|
||
)
|
||
|
||
// Redis kaç tane döküman buldu?
|
||
const totalFound = results[0] || 0
|
||
console.log(`📊 Redis Toplam Bulunan: ${totalFound}`)
|
||
|
||
const dealIds = parseSearchResults(results)
|
||
const runId = String(now)
|
||
const payload = {
|
||
id: runId,
|
||
createdAt: new Date(now).toISOString(),
|
||
total: dealIds.length,
|
||
dealIds,
|
||
}
|
||
|
||
const key = `deals:lists:trending:${runId}`
|
||
await redis.call("JSON.SET", key, "$", JSON.stringify(payload))
|
||
await redis.expire(key, TRENDING_DEAL_TTL_SECONDS)
|
||
await redis.set("deals:lists:trending:latest", runId, "EX", TRENDING_DEAL_TTL_SECONDS)
|
||
|
||
return { id: runId, total: dealIds.length }
|
||
} catch (error) {
|
||
console.error("❌ buildTrendingDealList Hatası:", error.message)
|
||
throw error
|
||
} finally {
|
||
redis.disconnect()
|
||
}
|
||
}
|
||
|
||
async function handler() {
|
||
return buildTrendingDealList()
|
||
}
|
||
|
||
function startTrendingDealListWorker() {
|
||
const worker = new Worker("trendingdeal-list", handler, {
|
||
connection: getRedisConnectionOptions(),
|
||
concurrency: 1,
|
||
})
|
||
|
||
worker.on("completed", (job) => {
|
||
console.log(`✅ Trending Deal Listesi Bitti. Bulunan ID Sayısı: ${job.returnvalue?.total}`)
|
||
})
|
||
|
||
worker.on("failed", (job, err) => {
|
||
console.error(`❌ Trending Deal Worker Hatası!`, err.message)
|
||
})
|
||
|
||
return worker
|
||
}
|
||
|
||
module.exports = { startTrendingDealListWorker }
|