/** * Outbox pressure management with telemetry */ import { OutboxPressureConfig, TelemetryMetrics } from './types'; import { DEFAULT_CONFIG } from './constants'; export class OutboxPressureManager { private config: OutboxPressureConfig; private metrics: TelemetryMetrics; constructor(config: Partial = {}) { this.config = { maxUndelivered: config.maxUndelivered ?? DEFAULT_CONFIG.maxUndelivered, cleanupIntervalMs: config.cleanupIntervalMs ?? DEFAULT_CONFIG.cleanupIntervalMs, backpressureThreshold: config.backpressureThreshold ?? DEFAULT_CONFIG.backpressureThreshold, evictionPolicy: config.evictionPolicy ?? 'fifo' }; this.metrics = { 'starred_projects_outbox_size': 0, 'starred_projects_outbox_backpressure_active': 0 } as TelemetryMetrics; } async checkStoragePressure(undeliveredCount: number): Promise { // Update metrics this.metrics['starred_projects_outbox_size'] = undeliveredCount; const pressureRatio = undeliveredCount / this.config.maxUndelivered; const backpressureActive = pressureRatio >= this.config.backpressureThreshold; // Update backpressure metric this.metrics['starred_projects_outbox_backpressure_active'] = backpressureActive ? 1 : 0; if (pressureRatio >= 1.0) { // Critical: Drop oldest notifications to make room const evictCount = undeliveredCount - this.config.maxUndelivered; await this.evictNotifications(evictCount); return true; // Backpressure active } return backpressureActive; } async evictNotifications(count: number): Promise { if (count <= 0) return; // Simulate eviction based on policy switch (this.config.evictionPolicy) { case 'fifo': await this.evictFIFO(count); break; case 'lifo': await this.evictLIFO(count); break; case 'priority': await this.evictByPriority(count); break; } } private async evictFIFO(count: number): Promise { // Simulate: DELETE FROM notification_outbox // WHERE delivered_at IS NULL // ORDER BY created_at ASC // LIMIT count console.log(`Evicting ${count} oldest notifications (FIFO)`); } private async evictLIFO(count: number): Promise { // Simulate: DELETE FROM notification_outbox // WHERE delivered_at IS NULL // ORDER BY created_at DESC // LIMIT count console.log(`Evicting ${count} newest notifications (LIFO)`); } private async evictByPriority(count: number): Promise { // Simulate: DELETE FROM notification_outbox // WHERE delivered_at IS NULL // ORDER BY priority ASC, created_at ASC // LIMIT count console.log(`Evicting ${count} lowest priority notifications`); } async cleanupDeliveredNotifications(): Promise { // Simulate: DELETE FROM notification_outbox // WHERE delivered_at IS NOT NULL // AND delivered_at < datetime('now', '-${cleanupIntervalMs / 1000} seconds') console.log(`Cleaning up delivered notifications older than ${this.config.cleanupIntervalMs}ms`); } getMetrics(): TelemetryMetrics { return { ...this.metrics }; } getConfig(): OutboxPressureConfig { return { ...this.config }; } } /** * Create default outbox pressure manager */ export function createDefaultOutboxPressureManager(): OutboxPressureManager { return new OutboxPressureManager(); } /** * Create outbox pressure manager with custom config */ export function createOutboxPressureManager(config: Partial): OutboxPressureManager { return new OutboxPressureManager(config); } /** * Outbox pressure configuration presets */ export const OUTBOX_PRESSURE_PRESETS = { // Conservative: Low memory usage, frequent cleanup conservative: { maxUndelivered: 500, backpressureThreshold: 0.7, cleanupIntervalMs: 1800000, // 30 minutes evictionPolicy: 'fifo' as const }, // Balanced: Good performance, reasonable memory usage balanced: { maxUndelivered: 1000, backpressureThreshold: 0.8, cleanupIntervalMs: 3600000, // 1 hour evictionPolicy: 'fifo' as const }, // Aggressive: High throughput, more memory usage aggressive: { maxUndelivered: 2000, backpressureThreshold: 0.9, cleanupIntervalMs: 7200000, // 2 hours evictionPolicy: 'priority' as const } } as const;