- Add notifications table with migration - Create NotificationService with area-of-interest matching - Integrate Mailgun for email delivery - Add notification API endpoints (get, mark as read, unread count) - Create scheduled jobs for event reminders and cleanup - Build NotificationBell component for frontend - Add notification triggers for reports and events - Implement comprehensive test script - Update Header with notification bell - Add email templates with HTML formatting Requirements satisfied: - 10.1: Users can define areas of interest (1-50km radius) - 10.2: Notifications sent within 10 minutes - 10.3: Notifications for new reports/events in user area - 10.4: Configurable notification preferences (email/in-app) Task 33 completed
98 lines
3.3 KiB
TypeScript
98 lines
3.3 KiB
TypeScript
/**
|
|
* Scheduled Jobs Service
|
|
* Manages periodic tasks using node-cron
|
|
*
|
|
* Requirement 3.4: Update Litter Hotspot calculations within 5 minutes of new report submissions
|
|
*/
|
|
|
|
import cron, { ScheduledTask } from 'node-cron';
|
|
import { analyticsService } from './analyticsService';
|
|
import { notificationService } from './notificationService';
|
|
|
|
/**
|
|
* Initialize all scheduled jobs
|
|
*/
|
|
export function initializeScheduledJobs() {
|
|
console.log('[Scheduled Jobs] Initializing scheduled jobs...');
|
|
|
|
// Hotspot calculation job - runs every 5 minutes
|
|
// Requirement 3.4: Update hotspot calculations within 5 minutes
|
|
const hotspotJob = cron.schedule('*/5 * * * *', async () => {
|
|
try {
|
|
console.log('[Scheduled Jobs] Running hotspot calculation...');
|
|
const result = await analyticsService.calculateAndUpdateHotspots();
|
|
console.log(`[Scheduled Jobs] Hotspot calculation completed: ${result.hotspotsCalculated} hotspots calculated`);
|
|
} catch (error: any) {
|
|
console.error('[Scheduled Jobs] Error in hotspot calculation job:', error.message);
|
|
}
|
|
});
|
|
|
|
console.log('[Scheduled Jobs] ✓ Hotspot calculation job scheduled (every 5 minutes)');
|
|
|
|
// Event reminder job - runs every 10 minutes
|
|
// Requirement 10.2: Send notifications within 10 minutes
|
|
const eventReminderJob = cron.schedule('*/10 * * * *', async () => {
|
|
try {
|
|
console.log('[Scheduled Jobs] Checking for event reminders...');
|
|
const reminders = await notificationService.sendEventReminders();
|
|
console.log(`[Scheduled Jobs] Event reminders sent: ${reminders.length} notifications`);
|
|
} catch (error: any) {
|
|
console.error('[Scheduled Jobs] Error in event reminder job:', error.message);
|
|
}
|
|
});
|
|
|
|
console.log('[Scheduled Jobs] ✓ Event reminder job scheduled (every 10 minutes)');
|
|
|
|
// Notification cleanup job - runs daily at 2 AM
|
|
const notificationCleanupJob = cron.schedule('0 2 * * *', async () => {
|
|
try {
|
|
console.log('[Scheduled Jobs] Cleaning up old notifications...');
|
|
const count = await notificationService.cleanupOldNotifications();
|
|
console.log(`[Scheduled Jobs] Notification cleanup completed: ${count} notifications deleted`);
|
|
} catch (error: any) {
|
|
console.error('[Scheduled Jobs] Error in notification cleanup job:', error.message);
|
|
}
|
|
});
|
|
|
|
console.log('[Scheduled Jobs] ✓ Notification cleanup job scheduled (daily at 2 AM)');
|
|
|
|
// Return job instances for potential management
|
|
return {
|
|
hotspotJob,
|
|
eventReminderJob,
|
|
notificationCleanupJob,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Stop all scheduled jobs
|
|
* Useful for graceful shutdown
|
|
*/
|
|
export function stopScheduledJobs(jobs: {
|
|
hotspotJob: ScheduledTask;
|
|
eventReminderJob: ScheduledTask;
|
|
notificationCleanupJob: ScheduledTask;
|
|
}) {
|
|
console.log('[Scheduled Jobs] Stopping all scheduled jobs...');
|
|
|
|
if (jobs.hotspotJob) {
|
|
jobs.hotspotJob.stop();
|
|
console.log('[Scheduled Jobs] ✓ Hotspot calculation job stopped');
|
|
}
|
|
|
|
if (jobs.eventReminderJob) {
|
|
jobs.eventReminderJob.stop();
|
|
console.log('[Scheduled Jobs] ✓ Event reminder job stopped');
|
|
}
|
|
|
|
if (jobs.notificationCleanupJob) {
|
|
jobs.notificationCleanupJob.stop();
|
|
console.log('[Scheduled Jobs] ✓ Notification cleanup job stopped');
|
|
}
|
|
}
|
|
|
|
export default {
|
|
initializeScheduledJobs,
|
|
stopScheduledJobs,
|
|
};
|