redis-smq
Version:
A high-performance, reliable, and scalable message queue for Node.js.
203 lines • 8.52 kB
JavaScript
import { async, CallbackEmptyReplyError, } from 'redis-smq-common';
import { redisKeys } from '../../common/redis/redis-keys/redis-keys.js';
import { _parseQueueExtendedParams } from '../../queue-manager/_/_parse-queue-extended-params.js';
import { _validateQueueExtendedParams } from './_/_validate-queue-extended-params.js';
import { withSharedPoolConnection } from '../../common/redis/redis-connection-pool/with-shared-pool-connection.js';
import { InvalidPurgeQueueJobIdError } from '../../errors/index.js';
import { PurgeQueueJobManager } from '../../common/background-jobs/jobs/purge-queue/purge-queue-job-manager.js';
import { EQueueOperation } from '../../queue-operation-validator/index.js';
import { _validateOperation } from '../../queue-operation-validator/_/_validate-operation.js';
import { _getMessageIds } from './_/_get-message-ids.js';
export class MessageBrowser {
redisKey;
logger;
requireGroupId;
messageManager;
messageStorage;
messageType;
constructor(messageManager, messageStorage, messageType, redisKey, requireGroupId, logger) {
this.messageManager = messageManager;
this.messageStorage = messageStorage;
this.messageType = messageType;
this.logger = logger;
this.redisKey = redisKey;
this.requireGroupId = requireGroupId;
}
validatePurgeOperation(parsedParams, cb) {
withSharedPoolConnection((client, done) => {
_validateOperation(client, parsedParams.queueParams, EQueueOperation.PURGE, done);
}, cb);
}
createPurgeJob(parsedParams, cb) {
this.withPurgeQueueJobManager((purgeQueueJobManager, done) => {
const target = {
queue: parsedParams,
messageType: this.messageType,
};
purgeQueueJobManager.create(target, {}, (err, job) => {
if (err) {
this.logger.error(`Could not create purge job for queue ${parsedParams.queueParams.name}`, err);
done(err);
return;
}
done(null, job?.id);
});
}, cb);
}
isJobForQueue(job, parsedParams) {
return (job.payload.queue.queueParams.name === parsedParams.queueParams.name &&
job.payload.queue.queueParams.ns === parsedParams.queueParams.ns &&
job.payload.queue.groupId === parsedParams.groupId &&
job.payload.messageType === this.messageType);
}
withValidatedQueue(queue, operation, cb) {
const parsedParams = _parseQueueExtendedParams(queue);
if (parsedParams instanceof Error) {
this.logger.error(`Error parsing queue parameters: ${parsedParams.message}`);
cb(parsedParams);
return;
}
withSharedPoolConnection((client, done) => {
_validateQueueExtendedParams(client, parsedParams, this.requireGroupId, (err) => {
if (err) {
this.logger.error(`Error validating queue parameters: ${err.message}`);
done(err);
return;
}
operation(parsedParams, done);
});
}, cb);
}
withPurgeQueueJobManager(operation, cb) {
withSharedPoolConnection((client, done) => {
async.waterfall([
(next) => {
const purgeQueueJobManager = new PurgeQueueJobManager(client, this.logger);
purgeQueueJobManager.initialize((err) => {
if (err) {
next(err);
return;
}
next(null, purgeQueueJobManager);
});
},
operation,
], done);
}, cb);
}
purge(queue, cb) {
this.logger.info(`Purging queue messages for queue ${JSON.stringify(queue)}`);
this.withValidatedQueue(queue, (parsedParams, done) => {
this.validatePurgeOperation(parsedParams, (err) => {
if (err) {
done(err);
return;
}
this.createPurgeJob(parsedParams, done);
});
}, cb);
}
getPurgeJob(queue, jobId, cb) {
this.withValidatedQueue(queue, (parsedParams, done) => {
this.withPurgeQueueJobManager((purgeQueueJobManager, innerDone) => {
purgeQueueJobManager.get(jobId, (err, job) => {
if (err) {
innerDone(err);
return;
}
if (!job) {
innerDone(new CallbackEmptyReplyError());
return;
}
if (!this.isJobForQueue(job, parsedParams)) {
innerDone(new InvalidPurgeQueueJobIdError({
metadata: { jobId },
}));
return;
}
innerDone(null, job);
});
}, done);
}, cb);
}
getPurgeJobStatus(queue, jobId, cb) {
this.getPurgeJob(queue, jobId, (err, job) => {
if (err) {
cb(err);
return;
}
if (!job) {
cb(new CallbackEmptyReplyError());
return;
}
cb(null, job.status);
});
}
cancelPurge(queue, jobId, cb) {
this.withValidatedQueue(queue, (parsedParams, done) => {
this.withPurgeQueueJobManager((purgeQueueJobManager, innerDone) => {
purgeQueueJobManager.get(jobId, (err, job) => {
if (err) {
innerDone(err);
return;
}
if (!job || !this.isJobForQueue(job, parsedParams)) {
innerDone(new InvalidPurgeQueueJobIdError({
metadata: { jobId },
}));
return;
}
purgeQueueJobManager.cancel(jobId, (err) => innerDone(err));
});
}, done);
}, cb);
}
getMessages(queue, page, pageSize, cb) {
this.withValidatedQueue(queue, (parsedParams, done) => {
this.logger.debug(`Getting messages for ${parsedParams.queueParams.name}, page ${page}, size ${pageSize}`);
async.waterfall([
(next) => {
_getMessageIds(parsedParams, page, pageSize, this.redisKey, this.messageStorage, this.logger, next);
},
(pageResult, next) => {
if (pageResult.items.length === 0) {
next(null, { ...pageResult, items: [] });
return;
}
this.messageManager.getMessagesByIds(pageResult.items, (err, messages) => {
if (err) {
next(err);
return;
}
next(null, {
...pageResult,
items: messages ?? [],
});
});
},
], done);
}, cb);
}
countMessages(queue, cb) {
this.withValidatedQueue(queue, (parsedParams, done) => {
this.logger.debug(`Counting messages for ${parsedParams.queueParams.name}`);
const keys = redisKeys.getQueueKeys(parsedParams.queueParams.ns, parsedParams.queueParams.name, parsedParams.groupId);
const keyVal = keys[this.redisKey];
this.messageStorage.count(keyVal, (err, count) => {
if (err) {
this.logger.error(`Error counting messages: ${err.message}`);
done(err);
return;
}
this.logger.debug(`Queue ${parsedParams.queueParams.name} has ${count} messages`);
done(null, count);
});
}, cb);
}
getMessageIds(queue, page, pageSize, cb) {
this.withValidatedQueue(queue, (parsedParams, done) => {
_getMessageIds(parsedParams, page, pageSize, this.redisKey, this.messageStorage, this.logger, done);
}, cb);
}
}
//# sourceMappingURL=message-browser.js.map