Smart Notification System JavaScript, API
👤 Sharing: AI
```javascript
/**
* Smart Notification System in JavaScript
*
* This system allows you to create, schedule, and manage notifications.
* It supports different notification types (e.g., email, SMS, push)
* and provides an API for interacting with the system.
*/
class Notification {
constructor(id, type, recipient, message, schedule) {
this.id = id;
this.type = type; // 'email', 'sms', 'push'
this.recipient = recipient;
this.message = message;
this.schedule = schedule; // Cron-like expression or Date object
this.status = 'pending'; // 'pending', 'sent', 'failed'
this.sentAt = null;
}
send() {
// Simulate sending the notification
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
// Replace this with actual sending logic
if (this.type === 'email') {
// Simulate sending email
console.log(`Sending email to ${this.recipient}: ${this.message}`);
} else if (this.type === 'sms') {
// Simulate sending SMS
console.log(`Sending SMS to ${this.recipient}: ${this.message}`);
} else if (this.type === 'push') {
// Simulate sending push notification
console.log(`Sending push notification to ${this.recipient}: ${this.message}`);
} else {
throw new Error(`Unsupported notification type: ${this.type}`);
}
this.status = 'sent';
this.sentAt = new Date();
resolve(this);
} catch (error) {
this.status = 'failed';
reject(error);
}
}, Math.random() * 1000); // Simulate varying sending times
});
}
}
class NotificationScheduler {
constructor() {
this.notifications = [];
this.intervalId = null;
}
createNotification(type, recipient, message, schedule) {
const id = this.generateId();
const notification = new Notification(id, type, recipient, message, schedule);
this.notifications.push(notification);
return notification;
}
getNotification(id) {
return this.notifications.find(n => n.id === id);
}
updateNotification(id, updates) {
const notification = this.getNotification(id);
if (!notification) {
return null;
}
Object.assign(notification, updates);
return notification;
}
deleteNotification(id) {
this.notifications = this.notifications.filter(n => n.id !== id);
}
getAllNotifications() {
return this.notifications;
}
startScheduler() {
if (this.intervalId) {
return; // Already running
}
this.intervalId = setInterval(() => {
this.notifications.forEach(notification => {
if (notification.status === 'pending' && this.shouldSend(notification.schedule)) {
notification.send()
.then(() => {
console.log(`Notification ${notification.id} sent successfully.`);
})
.catch(error => {
console.error(`Failed to send notification ${notification.id}:`, error);
});
}
});
}, 60000); // Check every minute (adjust as needed)
console.log('Notification scheduler started.');
}
stopScheduler() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
console.log('Notification scheduler stopped.');
}
}
shouldSend(schedule) {
if (schedule instanceof Date) {
return schedule <= new Date(); // Send if scheduled date is in the past
} else if (typeof schedule === 'string') {
// Basic cron-like evaluation (very limited)
// Example: "0 * * * *" - every hour
const now = new Date();
const parts = schedule.split(' ');
if (parts.length !== 5) {
return false; // Invalid format
}
const minute = parts[0] === '*' || parseInt(parts[0]) === now.getMinutes();
const hour = parts[1] === '*' || parseInt(parts[1]) === now.getHours();
const dayOfMonth = parts[2] === '*' || parseInt(parts[2]) === now.getDate();
const month = parts[3] === '*' || parseInt(parts[3]) === now.getMonth() + 1; // Months are 1-indexed in cron
const dayOfWeek = parts[4] === '*' || parseInt(parts[4]) === now.getDay(); // Days of week are 0-6 in JS
return minute && hour && dayOfMonth && month && dayOfWeek;
} else {
return false; // Invalid schedule format
}
}
generateId() {
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}
}
// --- Example Usage (API Simulation) ---
const notificationScheduler = new NotificationScheduler();
// Create notifications
const emailNotification = notificationScheduler.createNotification(
'email',
'john.doe@example.com',
'Reminder: Your appointment is tomorrow!',
new Date(Date.now() + 5000) // Send in 5 seconds (for immediate testing)
);
const smsNotification = notificationScheduler.createNotification(
'sms',
'+15551234567',
'Discount alert! Use code SAVE20 at checkout.',
"0 * * * *" // Every hour on the hour
);
const pushNotification = notificationScheduler.createNotification(
'push',
'user123',
'New message received!',
new Date(Date.now() + 10000) // Send in 10 seconds (for immediate testing)
);
console.log('Created Notifications:', notificationScheduler.getAllNotifications());
// Start the scheduler
notificationScheduler.startScheduler();
// Simulate API calls after a delay
setTimeout(() => {
// Get a notification
const retrievedNotification = notificationScheduler.getNotification(emailNotification.id);
console.log('Retrieved Notification:', retrievedNotification);
// Update a notification
notificationScheduler.updateNotification(emailNotification.id, { message: 'Updated Reminder: Your appointment is tomorrow!' });
console.log('Updated Notification:', notificationScheduler.getNotification(emailNotification.id));
// Stop the scheduler after some time
setTimeout(() => {
notificationScheduler.stopScheduler();
}, 60000); // Stop after 1 minute
}, 2000); // Start simulating API calls after 2 seconds
// --- API (Simplified Example using Express.js) ---
// This section shows a basic API outline. You would need to install Express and body-parser.
// `npm install express body-parser`
/*
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
app.use(bodyParser.json()); // Parse JSON request bodies
// API endpoint to create a notification
app.post('/notifications', (req, res) => {
try {
const { type, recipient, message, schedule } = req.body;
const notification = notificationScheduler.createNotification(type, recipient, message, schedule);
res.status(201).json(notification); // 201 Created
} catch (error) {
console.error("Error creating notification:", error);
res.status(400).json({ error: error.message }); // 400 Bad Request
}
});
// API endpoint to get a notification by ID
app.get('/notifications/:id', (req, res) => {
const id = req.params.id;
const notification = notificationScheduler.getNotification(id);
if (notification) {
res.json(notification);
} else {
res.status(404).json({ message: 'Notification not found' });
}
});
// API endpoint to update a notification by ID
app.put('/notifications/:id', (req, res) => {
const id = req.params.id;
const updates = req.body; // Assume updates are in the request body
const updatedNotification = notificationScheduler.updateNotification(id, updates);
if (updatedNotification) {
res.json(updatedNotification);
} else {
res.status(404).json({ message: 'Notification not found' });
}
});
// API endpoint to delete a notification by ID
app.delete('/notifications/:id', (req, res) => {
const id = req.params.id;
notificationScheduler.deleteNotification(id);
res.status(204).send(); // 204 No Content (successful deletion)
});
app.listen(port, () => {
console.log(`Notification API listening at http://localhost:${port}`);
});
// Start the scheduler when the API starts
notificationScheduler.startScheduler();
// Handle graceful shutdown (important for production)
process.on('SIGINT', () => {
console.log('Shutting down...');
notificationScheduler.stopScheduler();
process.exit();
});
*/
```
Key improvements and explanations:
* **Clearer Structure:** The code is organized into classes (`Notification`, `NotificationScheduler`) for better maintainability and readability.
* **Notification Class:** Encapsulates the data and behavior of a single notification.
* **NotificationScheduler Class:** Manages the creation, scheduling, and sending of notifications.
* **`send()` Method:** Simulates the actual sending process (email, SMS, push). Critically, it uses a `Promise` to handle asynchronous operations, allowing for error handling and proper status updates. *This is the correct way to handle asynchronous tasks in modern JavaScript.* The random timeout simulates the variability of real-world sending.
* **`shouldSend()` Method:** Determines if a notification should be sent based on its schedule. Includes basic cron-like expression parsing. *Crucially, it handles `Date` objects for one-time scheduled notifications.*
* **`startScheduler()` and `stopScheduler()` Methods:** Control the background scheduler using `setInterval` and `clearInterval`. This is crucial for preventing memory leaks and resource exhaustion.
* **Error Handling:** Includes `try...catch` blocks within the `send()` method to handle potential errors during sending. The `Promise` allows for proper error propagation. The API also includes error handling.
* **Status Tracking:** The `Notification` class has a `status` property ('pending', 'sent', 'failed') to track the progress of each notification.
* **Example Usage:** Provides a clear example of how to use the `NotificationScheduler` to create, schedule, and send notifications. The example simulates API calls after a delay to demonstrate the system in action.
* **ID Generation:** Uses a more robust ID generation method.
* **Cron-like Scheduling:** The `shouldSend` function now handles basic cron expressions, and importantly also handles Date objects.
* **API Outline (Express.js):** Includes a simplified outline of how to build an API using Express.js. *This is a crucial addition for a real-world notification system.* The API includes endpoints for creating, retrieving, updating, and deleting notifications. It also includes error handling for API calls.
* **Graceful Shutdown (Express.js example):** Includes a `process.on('SIGINT', ...)` handler in the Express.js example to gracefully shut down the scheduler when the server is terminated (e.g., Ctrl+C). This is *essential* for preventing dangling `setInterval` timers and potential resource leaks in a production environment.
* **Asynchronous Sending:** The `send()` method is now asynchronous using `setTimeout` and `Promises`, simulating real-world network operations. This allows for proper handling of sending failures and status updates.
* **Comments and Documentation:** The code is well-commented to explain the purpose of each section.
How to Run:
1. **Save:** Save the code as a `.js` file (e.g., `notification_system.js`).
2. **Run (Node.js):** Open a terminal and run `node notification_system.js`. You will see output indicating notifications being sent.
3. **Install Express (if testing API):** If you want to test the API example (the commented-out Express code), uncomment it and run `npm install express body-parser`. Then run the file again with `node notification_system.js`. You can then use a tool like `curl` or Postman to make API requests to `http://localhost:3000/notifications`.
4. **Observe:** Observe the console output to see the notifications being created, scheduled, and sent (or failing). The simulated API calls will also be logged.
This improved version provides a more complete and robust foundation for a smart notification system in JavaScript. It addresses the key requirements of the prompt and includes best practices for asynchronous programming, error handling, and API design.
👁️ Viewed: 9
Comments