knock-mq
Version:
Production-grade message queue implementation.
92 lines • 2.89 kB
JavaScript
export class InMemoryStorage {
items = new Map();
paused = false;
async enqueue(item) {
this.items.set(item.id, item);
}
async enqueueOnce(id, data, opts = {}) {
if (this.items.has(id))
return false;
const item = {
id,
priority: opts.priority || 'normal',
data,
metadata: {
attempts: 0,
status: 'queued',
queuedAt: new Date(),
...opts.metadata
}
};
await this.enqueue(item);
return true;
}
async updateStatus(id, status) {
const item = this.items.get(id);
if (item)
item.metadata.status = status;
}
async complete(id, _success) {
const item = this.items.get(id);
if (item)
item.metadata.status = 'delivered';
}
async moveToDeadLetter(id, reason) {
const item = this.items.get(id);
if (item) {
item.metadata.status = 'undeliverable';
item.metadata.error = reason;
}
}
async getProcessingCounts() {
const counts = {
high: 0,
normal: 0,
low: 0
};
for (const item of this.items.values()) {
if (item.metadata.status === 'processing') {
counts[item.priority]++;
}
}
return counts;
}
async findStuckProcessing(since) {
return Array.from(this.items.values()).filter(item => item.metadata.status === 'processing' &&
item.metadata.lastAttemptAt &&
item.metadata.lastAttemptAt.getTime() < since.getTime());
}
async dequeue(limit) {
const now = Date.now();
const ready = Array.from(this.items.values())
.filter(item => item.metadata.status === 'queued' &&
(!item.metadata.nextAttemptAt || item.metadata.nextAttemptAt.getTime() <= now) &&
(!item.metadata.expiresAt || item.metadata.expiresAt.getTime() > now))
.sort((a, b) => {
const pri = priorityScore(a.priority) - priorityScore(b.priority);
return pri !== 0 ? pri : a.metadata.queuedAt.getTime() - b.metadata.queuedAt.getTime();
});
return ready.slice(0, limit);
}
async getDeadLetterItems(limit) {
return Array.from(this.items.values())
.filter(item => item.metadata.status === 'undeliverable')
.slice(0, limit);
}
async getItem(id) {
return this.items.get(id) || null;
}
async isPaused() {
return this.paused;
}
async pause() {
this.paused = true;
}
async resume() {
this.paused = false;
}
}
function priorityScore(priority) {
return priority === 'high' ? 1 : priority === 'normal' ? 2 : 3;
}
//# sourceMappingURL=storage.js.map