@agent-relay/storage 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter.d.ts +156 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +167 -0
- package/dist/adapter.js.map +1 -0
- package/dist/batched-sqlite-adapter.d.ts +75 -0
- package/dist/batched-sqlite-adapter.d.ts.map +1 -0
- package/dist/batched-sqlite-adapter.js +189 -0
- package/dist/batched-sqlite-adapter.js.map +1 -0
- package/dist/dead-letter-queue.d.ts +196 -0
- package/dist/dead-letter-queue.d.ts.map +1 -0
- package/dist/dead-letter-queue.js +427 -0
- package/dist/dead-letter-queue.js.map +1 -0
- package/dist/dlq-adapter.d.ts +195 -0
- package/dist/dlq-adapter.d.ts.map +1 -0
- package/dist/dlq-adapter.js +664 -0
- package/dist/dlq-adapter.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/sqlite-adapter.d.ts +113 -0
- package/dist/sqlite-adapter.d.ts.map +1 -0
- package/dist/sqlite-adapter.js +752 -0
- package/dist/sqlite-adapter.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dead Letter Queue (DLQ) for Agent Relay
|
|
3
|
+
*
|
|
4
|
+
* Captures failed message deliveries for inspection, retry, and debugging.
|
|
5
|
+
* Messages end up in DLQ when:
|
|
6
|
+
* - Delivery exceeds max retry attempts
|
|
7
|
+
* - TTL expires before successful delivery
|
|
8
|
+
* - Target agent disconnects during delivery
|
|
9
|
+
* - Signature verification fails
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Persistent storage (SQLite)
|
|
13
|
+
* - Configurable retention period
|
|
14
|
+
* - Manual retry capability
|
|
15
|
+
* - Failure categorization
|
|
16
|
+
* - Metrics and alerting hooks
|
|
17
|
+
*/
|
|
18
|
+
import type { Database as BetterSqlite3Database } from 'better-sqlite3';
|
|
19
|
+
export type DLQFailureReason = 'max_retries_exceeded' | 'ttl_expired' | 'connection_lost' | 'target_not_found' | 'signature_invalid' | 'payload_too_large' | 'rate_limited' | 'unknown';
|
|
20
|
+
export interface DeadLetter {
|
|
21
|
+
/** Unique identifier */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Original message ID */
|
|
24
|
+
messageId: string;
|
|
25
|
+
/** Sender agent/user */
|
|
26
|
+
from: string;
|
|
27
|
+
/** Intended recipient */
|
|
28
|
+
to: string;
|
|
29
|
+
/** Topic (for subscriptions) */
|
|
30
|
+
topic?: string;
|
|
31
|
+
/** Message kind */
|
|
32
|
+
kind: string;
|
|
33
|
+
/** Message body */
|
|
34
|
+
body: string;
|
|
35
|
+
/** Additional data */
|
|
36
|
+
data?: Record<string, unknown>;
|
|
37
|
+
/** Thread ID */
|
|
38
|
+
thread?: string;
|
|
39
|
+
/** Original send timestamp */
|
|
40
|
+
originalTs: number;
|
|
41
|
+
/** DLQ entry timestamp */
|
|
42
|
+
dlqTs: number;
|
|
43
|
+
/** Failure reason */
|
|
44
|
+
reason: DLQFailureReason;
|
|
45
|
+
/** Detailed error message */
|
|
46
|
+
errorMessage?: string;
|
|
47
|
+
/** Number of delivery attempts made */
|
|
48
|
+
attemptCount: number;
|
|
49
|
+
/** Last attempt timestamp */
|
|
50
|
+
lastAttemptTs?: number;
|
|
51
|
+
/** Retry count from DLQ */
|
|
52
|
+
dlqRetryCount: number;
|
|
53
|
+
/** Whether message has been acknowledged/processed */
|
|
54
|
+
acknowledged: boolean;
|
|
55
|
+
/** Acknowledgment timestamp */
|
|
56
|
+
acknowledgedTs?: number;
|
|
57
|
+
/** Who acknowledged (agent name or 'system') */
|
|
58
|
+
acknowledgedBy?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface DLQConfig {
|
|
61
|
+
/** Enable DLQ (default: true) */
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
/** Maximum retention period in hours (default: 168 = 7 days) */
|
|
64
|
+
retentionHours: number;
|
|
65
|
+
/** Maximum entries to keep (default: 10000) */
|
|
66
|
+
maxEntries: number;
|
|
67
|
+
/** Enable automatic cleanup (default: true) */
|
|
68
|
+
autoCleanup: boolean;
|
|
69
|
+
/** Cleanup interval in minutes (default: 60) */
|
|
70
|
+
cleanupIntervalMinutes: number;
|
|
71
|
+
/** Alert threshold - emit warning when DLQ size exceeds this */
|
|
72
|
+
alertThreshold: number;
|
|
73
|
+
}
|
|
74
|
+
export interface DLQStats {
|
|
75
|
+
totalEntries: number;
|
|
76
|
+
unacknowledged: number;
|
|
77
|
+
byReason: Record<DLQFailureReason, number>;
|
|
78
|
+
byTarget: Record<string, number>;
|
|
79
|
+
oldestEntryTs: number | null;
|
|
80
|
+
newestEntryTs: number | null;
|
|
81
|
+
avgRetryCount: number;
|
|
82
|
+
}
|
|
83
|
+
export interface DLQQuery {
|
|
84
|
+
/** Filter by recipient */
|
|
85
|
+
to?: string;
|
|
86
|
+
/** Filter by sender */
|
|
87
|
+
from?: string;
|
|
88
|
+
/** Filter by failure reason */
|
|
89
|
+
reason?: DLQFailureReason;
|
|
90
|
+
/** Filter by acknowledged status */
|
|
91
|
+
acknowledged?: boolean;
|
|
92
|
+
/** Filter entries after this timestamp */
|
|
93
|
+
afterTs?: number;
|
|
94
|
+
/** Filter entries before this timestamp */
|
|
95
|
+
beforeTs?: number;
|
|
96
|
+
/** Maximum results */
|
|
97
|
+
limit?: number;
|
|
98
|
+
/** Offset for pagination */
|
|
99
|
+
offset?: number;
|
|
100
|
+
/** Order by (default: dlqTs DESC) */
|
|
101
|
+
orderBy?: 'dlqTs' | 'originalTs' | 'attemptCount';
|
|
102
|
+
/** Order direction */
|
|
103
|
+
orderDir?: 'ASC' | 'DESC';
|
|
104
|
+
}
|
|
105
|
+
export declare class DeadLetterQueue {
|
|
106
|
+
private config;
|
|
107
|
+
private db;
|
|
108
|
+
private cleanupTimer?;
|
|
109
|
+
private alertCallback?;
|
|
110
|
+
constructor(db: BetterSqlite3Database, config?: Partial<DLQConfig>);
|
|
111
|
+
/**
|
|
112
|
+
* Initialize database schema.
|
|
113
|
+
*/
|
|
114
|
+
private initSchema;
|
|
115
|
+
/**
|
|
116
|
+
* Start automatic cleanup timer.
|
|
117
|
+
*/
|
|
118
|
+
private startCleanupTimer;
|
|
119
|
+
/**
|
|
120
|
+
* Stop cleanup timer.
|
|
121
|
+
*/
|
|
122
|
+
stopCleanupTimer(): void;
|
|
123
|
+
/**
|
|
124
|
+
* Set callback for alert threshold.
|
|
125
|
+
*/
|
|
126
|
+
onAlert(callback: (stats: DLQStats) => void): void;
|
|
127
|
+
/**
|
|
128
|
+
* Add a failed message to DLQ.
|
|
129
|
+
*/
|
|
130
|
+
add(messageId: string, envelope: {
|
|
131
|
+
from: string;
|
|
132
|
+
to: string;
|
|
133
|
+
topic?: string;
|
|
134
|
+
kind: string;
|
|
135
|
+
body: string;
|
|
136
|
+
data?: Record<string, unknown>;
|
|
137
|
+
thread?: string;
|
|
138
|
+
ts: number;
|
|
139
|
+
}, reason: DLQFailureReason, attemptCount: number, errorMessage?: string): DeadLetter;
|
|
140
|
+
/**
|
|
141
|
+
* Get a dead letter by ID.
|
|
142
|
+
*/
|
|
143
|
+
get(id: string): DeadLetter | null;
|
|
144
|
+
/**
|
|
145
|
+
* Query dead letters.
|
|
146
|
+
*/
|
|
147
|
+
query(query?: DLQQuery): DeadLetter[];
|
|
148
|
+
/**
|
|
149
|
+
* Acknowledge a dead letter (mark as processed).
|
|
150
|
+
*/
|
|
151
|
+
acknowledge(id: string, acknowledgedBy?: string): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Acknowledge multiple dead letters.
|
|
154
|
+
*/
|
|
155
|
+
acknowledgeMany(ids: string[], acknowledgedBy?: string): number;
|
|
156
|
+
/**
|
|
157
|
+
* Increment retry count for a dead letter.
|
|
158
|
+
*/
|
|
159
|
+
incrementRetry(id: string): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Remove a dead letter.
|
|
162
|
+
*/
|
|
163
|
+
remove(id: string): boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Get DLQ statistics.
|
|
166
|
+
*/
|
|
167
|
+
getStats(): DLQStats;
|
|
168
|
+
/**
|
|
169
|
+
* Cleanup old entries.
|
|
170
|
+
*/
|
|
171
|
+
cleanup(): {
|
|
172
|
+
removed: number;
|
|
173
|
+
reason: string;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Check if we've exceeded alert threshold and call alert callback.
|
|
177
|
+
*/
|
|
178
|
+
private checkAlertThreshold;
|
|
179
|
+
/**
|
|
180
|
+
* Convert database row to DeadLetter object.
|
|
181
|
+
*/
|
|
182
|
+
private rowToDeadLetter;
|
|
183
|
+
/**
|
|
184
|
+
* Export dead letters for external processing.
|
|
185
|
+
*/
|
|
186
|
+
export(query?: DLQQuery): string;
|
|
187
|
+
/**
|
|
188
|
+
* Get messages ready for retry (unacknowledged, low retry count).
|
|
189
|
+
*/
|
|
190
|
+
getRetryable(maxRetries?: number, limit?: number): DeadLetter[];
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Create a DLQ instance with the given database.
|
|
194
|
+
*/
|
|
195
|
+
export declare function createDeadLetterQueue(db: BetterSqlite3Database, config?: Partial<DLQConfig>): DeadLetterQueue;
|
|
196
|
+
//# sourceMappingURL=dead-letter-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dead-letter-queue.d.ts","sourceRoot":"","sources":["../src/dead-letter-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dead Letter Queue (DLQ) for Agent Relay
|
|
3
|
+
*
|
|
4
|
+
* Captures failed message deliveries for inspection, retry, and debugging.
|
|
5
|
+
* Messages end up in DLQ when:
|
|
6
|
+
* - Delivery exceeds max retry attempts
|
|
7
|
+
* - TTL expires before successful delivery
|
|
8
|
+
* - Target agent disconnects during delivery
|
|
9
|
+
* - Signature verification fails
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Persistent storage (SQLite)
|
|
13
|
+
* - Configurable retention period
|
|
14
|
+
* - Manual retry capability
|
|
15
|
+
* - Failure categorization
|
|
16
|
+
* - Metrics and alerting hooks
|
|
17
|
+
*/
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// Default Configuration
|
|
20
|
+
// =============================================================================
|
|
21
|
+
const DEFAULT_DLQ_CONFIG = {
|
|
22
|
+
enabled: true,
|
|
23
|
+
retentionHours: 168, // 7 days
|
|
24
|
+
maxEntries: 10000,
|
|
25
|
+
autoCleanup: true,
|
|
26
|
+
cleanupIntervalMinutes: 60,
|
|
27
|
+
alertThreshold: 1000,
|
|
28
|
+
};
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// DLQ Storage Schema
|
|
31
|
+
// =============================================================================
|
|
32
|
+
const DLQ_SCHEMA = `
|
|
33
|
+
CREATE TABLE IF NOT EXISTS dead_letters (
|
|
34
|
+
id TEXT PRIMARY KEY,
|
|
35
|
+
message_id TEXT NOT NULL,
|
|
36
|
+
from_agent TEXT NOT NULL,
|
|
37
|
+
to_agent TEXT NOT NULL,
|
|
38
|
+
topic TEXT,
|
|
39
|
+
kind TEXT NOT NULL,
|
|
40
|
+
body TEXT NOT NULL,
|
|
41
|
+
data TEXT,
|
|
42
|
+
thread TEXT,
|
|
43
|
+
original_ts INTEGER NOT NULL,
|
|
44
|
+
dlq_ts INTEGER NOT NULL,
|
|
45
|
+
reason TEXT NOT NULL,
|
|
46
|
+
error_message TEXT,
|
|
47
|
+
attempt_count INTEGER NOT NULL DEFAULT 0,
|
|
48
|
+
last_attempt_ts INTEGER,
|
|
49
|
+
dlq_retry_count INTEGER NOT NULL DEFAULT 0,
|
|
50
|
+
acknowledged INTEGER NOT NULL DEFAULT 0,
|
|
51
|
+
acknowledged_ts INTEGER,
|
|
52
|
+
acknowledged_by TEXT
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_to ON dead_letters(to_agent);
|
|
56
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_from ON dead_letters(from_agent);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_reason ON dead_letters(reason);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_ts ON dead_letters(dlq_ts);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_dlq_acknowledged ON dead_letters(acknowledged);
|
|
60
|
+
`;
|
|
61
|
+
// =============================================================================
|
|
62
|
+
// Dead Letter Queue Implementation
|
|
63
|
+
// =============================================================================
|
|
64
|
+
export class DeadLetterQueue {
|
|
65
|
+
config;
|
|
66
|
+
db;
|
|
67
|
+
cleanupTimer;
|
|
68
|
+
alertCallback;
|
|
69
|
+
constructor(db, config = {}) {
|
|
70
|
+
this.config = { ...DEFAULT_DLQ_CONFIG, ...config };
|
|
71
|
+
this.db = db;
|
|
72
|
+
// Initialize schema
|
|
73
|
+
this.initSchema();
|
|
74
|
+
// Start cleanup timer if enabled
|
|
75
|
+
if (this.config.autoCleanup) {
|
|
76
|
+
this.startCleanupTimer();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Initialize database schema.
|
|
81
|
+
*/
|
|
82
|
+
initSchema() {
|
|
83
|
+
this.db.exec(DLQ_SCHEMA);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Start automatic cleanup timer.
|
|
87
|
+
*/
|
|
88
|
+
startCleanupTimer() {
|
|
89
|
+
const intervalMs = this.config.cleanupIntervalMinutes * 60 * 1000;
|
|
90
|
+
this.cleanupTimer = setInterval(() => {
|
|
91
|
+
this.cleanup();
|
|
92
|
+
}, intervalMs);
|
|
93
|
+
// Don't block process exit
|
|
94
|
+
this.cleanupTimer.unref();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Stop cleanup timer.
|
|
98
|
+
*/
|
|
99
|
+
stopCleanupTimer() {
|
|
100
|
+
if (this.cleanupTimer) {
|
|
101
|
+
clearInterval(this.cleanupTimer);
|
|
102
|
+
this.cleanupTimer = undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Set callback for alert threshold.
|
|
107
|
+
*/
|
|
108
|
+
onAlert(callback) {
|
|
109
|
+
this.alertCallback = callback;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Add a failed message to DLQ.
|
|
113
|
+
*/
|
|
114
|
+
add(messageId, envelope, reason, attemptCount, errorMessage) {
|
|
115
|
+
if (!this.config.enabled) {
|
|
116
|
+
throw new Error('DLQ is disabled');
|
|
117
|
+
}
|
|
118
|
+
const id = `dlq_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
119
|
+
const now = Date.now();
|
|
120
|
+
const deadLetter = {
|
|
121
|
+
id,
|
|
122
|
+
messageId,
|
|
123
|
+
from: envelope.from,
|
|
124
|
+
to: envelope.to,
|
|
125
|
+
topic: envelope.topic,
|
|
126
|
+
kind: envelope.kind,
|
|
127
|
+
body: envelope.body,
|
|
128
|
+
data: envelope.data,
|
|
129
|
+
thread: envelope.thread,
|
|
130
|
+
originalTs: envelope.ts,
|
|
131
|
+
dlqTs: now,
|
|
132
|
+
reason,
|
|
133
|
+
errorMessage,
|
|
134
|
+
attemptCount,
|
|
135
|
+
lastAttemptTs: now,
|
|
136
|
+
dlqRetryCount: 0,
|
|
137
|
+
acknowledged: false,
|
|
138
|
+
};
|
|
139
|
+
const stmt = this.db.prepare(`
|
|
140
|
+
INSERT INTO dead_letters (
|
|
141
|
+
id, message_id, from_agent, to_agent, topic, kind, body, data, thread,
|
|
142
|
+
original_ts, dlq_ts, reason, error_message, attempt_count, last_attempt_ts,
|
|
143
|
+
dlq_retry_count, acknowledged
|
|
144
|
+
) VALUES (
|
|
145
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
146
|
+
)
|
|
147
|
+
`);
|
|
148
|
+
stmt.run(deadLetter.id, deadLetter.messageId, deadLetter.from, deadLetter.to, deadLetter.topic ?? null, deadLetter.kind, deadLetter.body, deadLetter.data ? JSON.stringify(deadLetter.data) : null, deadLetter.thread ?? null, deadLetter.originalTs, deadLetter.dlqTs, deadLetter.reason, deadLetter.errorMessage ?? null, deadLetter.attemptCount, deadLetter.lastAttemptTs ?? null, deadLetter.dlqRetryCount, deadLetter.acknowledged ? 1 : 0);
|
|
149
|
+
console.log(`[dlq] Added dead letter ${id} for message ${messageId}: ${reason}`);
|
|
150
|
+
// Check alert threshold
|
|
151
|
+
this.checkAlertThreshold();
|
|
152
|
+
return deadLetter;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get a dead letter by ID.
|
|
156
|
+
*/
|
|
157
|
+
get(id) {
|
|
158
|
+
const stmt = this.db.prepare('SELECT * FROM dead_letters WHERE id = ?');
|
|
159
|
+
const row = stmt.get(id);
|
|
160
|
+
if (!row)
|
|
161
|
+
return null;
|
|
162
|
+
return this.rowToDeadLetter(row);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Query dead letters.
|
|
166
|
+
*/
|
|
167
|
+
query(query = {}) {
|
|
168
|
+
const conditions = [];
|
|
169
|
+
const params = [];
|
|
170
|
+
if (query.to) {
|
|
171
|
+
conditions.push('to_agent = ?');
|
|
172
|
+
params.push(query.to);
|
|
173
|
+
}
|
|
174
|
+
if (query.from) {
|
|
175
|
+
conditions.push('from_agent = ?');
|
|
176
|
+
params.push(query.from);
|
|
177
|
+
}
|
|
178
|
+
if (query.reason) {
|
|
179
|
+
conditions.push('reason = ?');
|
|
180
|
+
params.push(query.reason);
|
|
181
|
+
}
|
|
182
|
+
if (query.acknowledged !== undefined) {
|
|
183
|
+
conditions.push('acknowledged = ?');
|
|
184
|
+
params.push(query.acknowledged ? 1 : 0);
|
|
185
|
+
}
|
|
186
|
+
if (query.afterTs) {
|
|
187
|
+
conditions.push('dlq_ts > ?');
|
|
188
|
+
params.push(query.afterTs);
|
|
189
|
+
}
|
|
190
|
+
if (query.beforeTs) {
|
|
191
|
+
conditions.push('dlq_ts < ?');
|
|
192
|
+
params.push(query.beforeTs);
|
|
193
|
+
}
|
|
194
|
+
const whereClause = conditions.length > 0
|
|
195
|
+
? `WHERE ${conditions.join(' AND ')}`
|
|
196
|
+
: '';
|
|
197
|
+
const orderBy = query.orderBy ?? 'dlq_ts';
|
|
198
|
+
const orderDir = query.orderDir ?? 'DESC';
|
|
199
|
+
const orderColumn = orderBy === 'dlqTs' ? 'dlq_ts'
|
|
200
|
+
: orderBy === 'originalTs' ? 'original_ts'
|
|
201
|
+
: 'attempt_count';
|
|
202
|
+
const limit = query.limit ?? 100;
|
|
203
|
+
const offset = query.offset ?? 0;
|
|
204
|
+
const sql = `
|
|
205
|
+
SELECT * FROM dead_letters
|
|
206
|
+
${whereClause}
|
|
207
|
+
ORDER BY ${orderColumn} ${orderDir}
|
|
208
|
+
LIMIT ? OFFSET ?
|
|
209
|
+
`;
|
|
210
|
+
params.push(limit, offset);
|
|
211
|
+
const stmt = this.db.prepare(sql);
|
|
212
|
+
const rows = stmt.all(...params);
|
|
213
|
+
return rows.map(row => this.rowToDeadLetter(row));
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Acknowledge a dead letter (mark as processed).
|
|
217
|
+
*/
|
|
218
|
+
acknowledge(id, acknowledgedBy = 'system') {
|
|
219
|
+
const stmt = this.db.prepare(`
|
|
220
|
+
UPDATE dead_letters
|
|
221
|
+
SET acknowledged = 1, acknowledged_ts = ?, acknowledged_by = ?
|
|
222
|
+
WHERE id = ? AND acknowledged = 0
|
|
223
|
+
`);
|
|
224
|
+
const result = stmt.run(Date.now(), acknowledgedBy, id);
|
|
225
|
+
return result.changes > 0;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Acknowledge multiple dead letters.
|
|
229
|
+
*/
|
|
230
|
+
acknowledgeMany(ids, acknowledgedBy = 'system') {
|
|
231
|
+
const placeholders = ids.map(() => '?').join(',');
|
|
232
|
+
const stmt = this.db.prepare(`
|
|
233
|
+
UPDATE dead_letters
|
|
234
|
+
SET acknowledged = 1, acknowledged_ts = ?, acknowledged_by = ?
|
|
235
|
+
WHERE id IN (${placeholders}) AND acknowledged = 0
|
|
236
|
+
`);
|
|
237
|
+
const result = stmt.run(Date.now(), acknowledgedBy, ...ids);
|
|
238
|
+
return result.changes;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Increment retry count for a dead letter.
|
|
242
|
+
*/
|
|
243
|
+
incrementRetry(id) {
|
|
244
|
+
const stmt = this.db.prepare(`
|
|
245
|
+
UPDATE dead_letters
|
|
246
|
+
SET dlq_retry_count = dlq_retry_count + 1, last_attempt_ts = ?
|
|
247
|
+
WHERE id = ?
|
|
248
|
+
`);
|
|
249
|
+
const result = stmt.run(Date.now(), id);
|
|
250
|
+
return result.changes > 0;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Remove a dead letter.
|
|
254
|
+
*/
|
|
255
|
+
remove(id) {
|
|
256
|
+
const stmt = this.db.prepare('DELETE FROM dead_letters WHERE id = ?');
|
|
257
|
+
const result = stmt.run(id);
|
|
258
|
+
return result.changes > 0;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get DLQ statistics.
|
|
262
|
+
*/
|
|
263
|
+
getStats() {
|
|
264
|
+
const totalStmt = this.db.prepare('SELECT COUNT(*) as count FROM dead_letters');
|
|
265
|
+
const totalRow = totalStmt.get();
|
|
266
|
+
const unackStmt = this.db.prepare('SELECT COUNT(*) as count FROM dead_letters WHERE acknowledged = 0');
|
|
267
|
+
const unackRow = unackStmt.get();
|
|
268
|
+
const byReasonStmt = this.db.prepare(`
|
|
269
|
+
SELECT reason, COUNT(*) as count
|
|
270
|
+
FROM dead_letters
|
|
271
|
+
GROUP BY reason
|
|
272
|
+
`);
|
|
273
|
+
const reasonRows = byReasonStmt.all();
|
|
274
|
+
const byReason = {
|
|
275
|
+
max_retries_exceeded: 0,
|
|
276
|
+
ttl_expired: 0,
|
|
277
|
+
connection_lost: 0,
|
|
278
|
+
target_not_found: 0,
|
|
279
|
+
signature_invalid: 0,
|
|
280
|
+
payload_too_large: 0,
|
|
281
|
+
rate_limited: 0,
|
|
282
|
+
unknown: 0,
|
|
283
|
+
};
|
|
284
|
+
for (const row of reasonRows) {
|
|
285
|
+
byReason[row.reason] = row.count;
|
|
286
|
+
}
|
|
287
|
+
const byTargetStmt = this.db.prepare(`
|
|
288
|
+
SELECT to_agent, COUNT(*) as count
|
|
289
|
+
FROM dead_letters
|
|
290
|
+
GROUP BY to_agent
|
|
291
|
+
ORDER BY count DESC
|
|
292
|
+
LIMIT 10
|
|
293
|
+
`);
|
|
294
|
+
const targetRows = byTargetStmt.all();
|
|
295
|
+
const byTarget = {};
|
|
296
|
+
for (const row of targetRows) {
|
|
297
|
+
byTarget[row.to_agent] = row.count;
|
|
298
|
+
}
|
|
299
|
+
const oldestStmt = this.db.prepare('SELECT MIN(dlq_ts) as ts FROM dead_letters WHERE acknowledged = 0');
|
|
300
|
+
const oldestRow = oldestStmt.get();
|
|
301
|
+
const newestStmt = this.db.prepare('SELECT MAX(dlq_ts) as ts FROM dead_letters WHERE acknowledged = 0');
|
|
302
|
+
const newestRow = newestStmt.get();
|
|
303
|
+
const avgRetryStmt = this.db.prepare('SELECT AVG(dlq_retry_count) as avg FROM dead_letters');
|
|
304
|
+
const avgRow = avgRetryStmt.get();
|
|
305
|
+
return {
|
|
306
|
+
totalEntries: totalRow.count,
|
|
307
|
+
unacknowledged: unackRow.count,
|
|
308
|
+
byReason,
|
|
309
|
+
byTarget,
|
|
310
|
+
oldestEntryTs: oldestRow.ts,
|
|
311
|
+
newestEntryTs: newestRow.ts,
|
|
312
|
+
avgRetryCount: avgRow.avg ?? 0,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Cleanup old entries.
|
|
317
|
+
*/
|
|
318
|
+
cleanup() {
|
|
319
|
+
const now = Date.now();
|
|
320
|
+
const cutoffTs = now - this.config.retentionHours * 3600 * 1000;
|
|
321
|
+
// Remove old acknowledged entries first
|
|
322
|
+
const oldAckStmt = this.db.prepare(`
|
|
323
|
+
DELETE FROM dead_letters
|
|
324
|
+
WHERE acknowledged = 1 AND dlq_ts < ?
|
|
325
|
+
`);
|
|
326
|
+
const oldAckResult = oldAckStmt.run(cutoffTs);
|
|
327
|
+
// Remove entries beyond retention (even if unacknowledged)
|
|
328
|
+
const retentionStmt = this.db.prepare(`
|
|
329
|
+
DELETE FROM dead_letters
|
|
330
|
+
WHERE dlq_ts < ?
|
|
331
|
+
`);
|
|
332
|
+
const retentionResult = retentionStmt.run(cutoffTs);
|
|
333
|
+
// Enforce max entries limit
|
|
334
|
+
const countStmt = this.db.prepare('SELECT COUNT(*) as count FROM dead_letters');
|
|
335
|
+
const countRow = countStmt.get();
|
|
336
|
+
let maxEntriesRemoved = 0;
|
|
337
|
+
if (countRow.count > this.config.maxEntries) {
|
|
338
|
+
const excess = countRow.count - this.config.maxEntries;
|
|
339
|
+
const trimStmt = this.db.prepare(`
|
|
340
|
+
DELETE FROM dead_letters
|
|
341
|
+
WHERE id IN (
|
|
342
|
+
SELECT id FROM dead_letters
|
|
343
|
+
WHERE acknowledged = 1
|
|
344
|
+
ORDER BY dlq_ts ASC
|
|
345
|
+
LIMIT ?
|
|
346
|
+
)
|
|
347
|
+
`);
|
|
348
|
+
const trimResult = trimStmt.run(excess);
|
|
349
|
+
maxEntriesRemoved = trimResult.changes;
|
|
350
|
+
}
|
|
351
|
+
const totalRemoved = oldAckResult.changes + retentionResult.changes + maxEntriesRemoved;
|
|
352
|
+
if (totalRemoved > 0) {
|
|
353
|
+
console.log(`[dlq] Cleanup removed ${totalRemoved} entries`);
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
removed: totalRemoved,
|
|
357
|
+
reason: `retention=${retentionResult.changes}, maxEntries=${maxEntriesRemoved}`,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Check if we've exceeded alert threshold and call alert callback.
|
|
362
|
+
*/
|
|
363
|
+
checkAlertThreshold() {
|
|
364
|
+
if (!this.alertCallback)
|
|
365
|
+
return;
|
|
366
|
+
const stats = this.getStats();
|
|
367
|
+
if (stats.unacknowledged >= this.config.alertThreshold) {
|
|
368
|
+
this.alertCallback(stats);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Convert database row to DeadLetter object.
|
|
373
|
+
*/
|
|
374
|
+
rowToDeadLetter(row) {
|
|
375
|
+
return {
|
|
376
|
+
id: row.id,
|
|
377
|
+
messageId: row.message_id,
|
|
378
|
+
from: row.from_agent,
|
|
379
|
+
to: row.to_agent,
|
|
380
|
+
topic: row.topic,
|
|
381
|
+
kind: row.kind,
|
|
382
|
+
body: row.body,
|
|
383
|
+
data: row.data ? JSON.parse(row.data) : undefined,
|
|
384
|
+
thread: row.thread,
|
|
385
|
+
originalTs: row.original_ts,
|
|
386
|
+
dlqTs: row.dlq_ts,
|
|
387
|
+
reason: row.reason,
|
|
388
|
+
errorMessage: row.error_message,
|
|
389
|
+
attemptCount: row.attempt_count,
|
|
390
|
+
lastAttemptTs: row.last_attempt_ts,
|
|
391
|
+
dlqRetryCount: row.dlq_retry_count,
|
|
392
|
+
acknowledged: row.acknowledged === 1,
|
|
393
|
+
acknowledgedTs: row.acknowledged_ts,
|
|
394
|
+
acknowledgedBy: row.acknowledged_by,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Export dead letters for external processing.
|
|
399
|
+
*/
|
|
400
|
+
export(query = {}) {
|
|
401
|
+
const letters = this.query(query);
|
|
402
|
+
return JSON.stringify(letters, null, 2);
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Get messages ready for retry (unacknowledged, low retry count).
|
|
406
|
+
*/
|
|
407
|
+
getRetryable(maxRetries = 3, limit = 10) {
|
|
408
|
+
const stmt = this.db.prepare(`
|
|
409
|
+
SELECT * FROM dead_letters
|
|
410
|
+
WHERE acknowledged = 0 AND dlq_retry_count < ?
|
|
411
|
+
ORDER BY dlq_ts ASC
|
|
412
|
+
LIMIT ?
|
|
413
|
+
`);
|
|
414
|
+
const rows = stmt.all(maxRetries, limit);
|
|
415
|
+
return rows.map(row => this.rowToDeadLetter(row));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// =============================================================================
|
|
419
|
+
// Factory Function
|
|
420
|
+
// =============================================================================
|
|
421
|
+
/**
|
|
422
|
+
* Create a DLQ instance with the given database.
|
|
423
|
+
*/
|
|
424
|
+
export function createDeadLetterQueue(db, config) {
|
|
425
|
+
return new DeadLetterQueue(db, config);
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=dead-letter-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dead-letter-queue.js","sourceRoot":"","sources":["../src/dead-letter-queue.ts"],"names":[],"mappings":"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"}
|