HotTRDealsBackend/services/redis/scraperRpc.service.js
2026-02-09 21:47:55 +00:00

98 lines
2.8 KiB
JavaScript

const Redis = require("ioredis")
const { randomUUID } = require("crypto")
const { getRedisClient } = require("./client")
const { getRedisConnectionOptions } = require("./connection")
const DEFAULT_QUEUE_KEY = "scraper:requests"
const DEFAULT_RESPONSE_CHANNEL_PREFIX = "scraper:response:"
const DEFAULT_TIMEOUT_MS = 20000
function normalizeTimeoutMs(value) {
const num = Number(value)
if (!Number.isFinite(num) || num < 1000) return DEFAULT_TIMEOUT_MS
return Math.floor(num)
}
async function requestProductPreviewOverRedis(url, options = {}) {
if (!url) throw new Error("url parametresi zorunlu")
const queueKey = process.env.SCRAPER_QUEUE_KEY || DEFAULT_QUEUE_KEY
const responsePrefix =
process.env.SCRAPER_RESPONSE_CHANNEL_PREFIX || DEFAULT_RESPONSE_CHANNEL_PREFIX
const timeoutMs = normalizeTimeoutMs(
options.timeoutMs ?? process.env.SCRAPER_RPC_TIMEOUT_MS
)
const requestId = randomUUID()
const responseChannel = `${responsePrefix}${requestId}`
const redis = getRedisClient()
const subscriber = new Redis(getRedisConnectionOptions())
const requestPayload = {
requestId,
type: "PRODUCT_PREVIEW",
url: String(url),
createdAt: new Date().toISOString(),
}
let timeoutHandle = null
let settled = false
function finish() {
if (timeoutHandle) {
clearTimeout(timeoutHandle)
timeoutHandle = null
}
subscriber.removeAllListeners("message")
subscriber
.unsubscribe(responseChannel)
.catch(() => {})
.finally(() => subscriber.disconnect())
}
return new Promise(async (resolve, reject) => {
const safeResolve = (data) => {
if (settled) return
settled = true
finish()
resolve(data)
}
const safeReject = (err) => {
if (settled) return
settled = true
finish()
reject(err)
}
try {
subscriber.on("message", (channel, rawMessage) => {
if (channel !== responseChannel) return
try {
const parsed = JSON.parse(String(rawMessage || "{}"))
if (parsed?.error) {
return safeReject(new Error(String(parsed.error)))
}
if (parsed && typeof parsed === "object" && parsed.product) {
return safeResolve(parsed.product)
}
return safeResolve(parsed)
} catch {
return safeReject(new Error("Scraper yaniti parse edilemedi"))
}
})
await subscriber.subscribe(responseChannel)
await redis.rpush(queueKey, JSON.stringify(requestPayload))
timeoutHandle = setTimeout(() => {
safeReject(new Error("Scraper yaniti zaman asimina ugradi"))
}, timeoutMs)
} catch (err) {
safeReject(err instanceof Error ? err : new Error("Scraper RPC hatasi"))
}
})
}
module.exports = { requestProductPreviewOverRedis }