68 lines
2.7 KiB
JavaScript
68 lines
2.7 KiB
JavaScript
import schedule from "node-cron";
|
|
import { insert, execute } from "../db/queryHelper/index.js";
|
|
import { getIO, getSocketId } from "../socket.js";
|
|
|
|
// Run every hour
|
|
export const startExpirationJob = () => {
|
|
schedule.schedule("0 * * * *", async () => {
|
|
console.log("Running listing expiration check...");
|
|
try {
|
|
const result = await execute({
|
|
type: 'transaction',
|
|
handler: async (trx) => {
|
|
// 1. Identify expired listings (active & not updated in last 48h)
|
|
const expiredListings = await trx('listings')
|
|
.select('id', 'title', 'seller_id')
|
|
.where({ status: 'active', deleted: false })
|
|
.whereRaw("updated_at < NOW() - INTERVAL '48 hours'")
|
|
.forUpdate()
|
|
.skipLocked();
|
|
|
|
if (expiredListings.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
console.log(`Found ${expiredListings.length} listings to expire.`);
|
|
|
|
// 2. Update status to 'expired'
|
|
const expiredIds = expiredListings.map(l => l.id);
|
|
await trx('listings')
|
|
.whereIn('id', expiredIds)
|
|
.update({ status: 'expired' });
|
|
|
|
// 3. Create Notifications & Real-time Alerts
|
|
for (const listing of expiredListings) {
|
|
const message = `Your listing "${listing.title}" has expired after 48 hours of inactivity. Click here to re-list it.`;
|
|
|
|
// Insert Notification
|
|
await trx('notifications').insert({
|
|
user_id: listing.seller_id,
|
|
type: 'listing_expired',
|
|
message,
|
|
data: { listing_id: listing.id }
|
|
});
|
|
|
|
// Real-time Socket Emit
|
|
const socketId = getSocketId(listing.seller_id);
|
|
if (socketId) {
|
|
getIO().to(socketId).emit("notification", {
|
|
type: "listing_expired",
|
|
message,
|
|
data: { listing_id: listing.id }
|
|
});
|
|
}
|
|
}
|
|
|
|
return expiredListings;
|
|
}
|
|
});
|
|
|
|
if (result && result.length > 0) {
|
|
console.log("Expiration check completed successfully.");
|
|
}
|
|
} catch (err) {
|
|
console.error("Error in expiration job:", err);
|
|
}
|
|
});
|
|
};
|