feat: Add real-time notification center with WebSocket integration
- Add in-app notification system with database storage - Implement bell icon component with unread count badge in dashboard header - Add full Notifications page tab with pagination and filtering (All/Unread/Read) - Implement real-time WebSocket push notifications to all connected clients - Add notification API endpoints: GET, PUT /read, DELETE, POST /clear - Fix critical bug in notificationService where 'status' variable was undefined - Add Notifications route to App.js routing - Enhanced UI with notification popup in header and dedicated full-page view - Auto-reconnect WebSocket with 5s timeout on disconnect - Support rich notification content with resource details and timestamps
This commit is contained in:
1 parent
7968c9231e
commit
db85573986
37 files changed
+3521
-207
No files matched your search
@@ -0,0 +1,62 @@
|
||||
// Circuit breaker implementation for API resilience
|
||||
class CircuitBreaker {
|
||||
constructor(failureThreshold = 5, resetTimeout = 60000, errorFilter = null) {
|
||||
this.failureThreshold = failureThreshold;
|
||||
this.resetTimeout = resetTimeout;
|
||||
this.errorFilter = errorFilter;
|
||||
this.failureCount = 0;
|
||||
this.lastFailureTime = null;
|
||||
this.state = 'closed'; // closed, open, half-open
|
||||
}
|
||||
|
||||
async execute(fn, fallback = null) {
|
||||
if (this.state === 'open') {
|
||||
if (Date.now() - this.lastFailureTime > this.resetTimeout) {
|
||||
this.state = 'half-open';
|
||||
} else {
|
||||
if (fallback) return fallback();
|
||||
throw new Error('Circuit breaker is open');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await fn();
|
||||
if (this.state === 'half-open') {
|
||||
this.close();
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (this.errorFilter && !this.errorFilter(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.failureCount++;
|
||||
this.lastFailureTime = Date.now();
|
||||
|
||||
if (this.failureCount >= this.failureThreshold) {
|
||||
this.open();
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this.failureCount = 0;
|
||||
this.state = 'closed';
|
||||
}
|
||||
|
||||
open() {
|
||||
this.state = 'open';
|
||||
}
|
||||
|
||||
getState() {
|
||||
return {
|
||||
state: this.state,
|
||||
failureCount: this.failureCount,
|
||||
lastFailureTime: this.lastFailureTime
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CircuitBreaker;
|
||||
Reference in new issue
Block a user