@bitblit/ratchet-epsilon-common
Version:
Tiny adapter to simplify building API gateway Lambda APIS
151 lines • 6.36 kB
JavaScript
import { Logger } from '@bitblit/ratchet-common/logger/logger';
import { ErrorRatchet } from '@bitblit/ratchet-common/lang/error-ratchet';
import { DeleteMessageCommand, GetQueueAttributesCommand, ReceiveMessageCommand, SendMessageCommand, } from '@aws-sdk/client-sqs';
import { EpsilonConstants } from '../../epsilon-constants.js';
import { AbstractBackgroundManager } from './abstract-background-manager.js';
import { BackgroundValidator } from '../background-validator.js';
import { PublishCommand } from '@aws-sdk/client-sns';
import { NumberRatchet } from '@bitblit/ratchet-common/lang/number-ratchet';
export class AwsSqsSnsBackgroundManager extends AbstractBackgroundManager {
_awsConfig;
_sqs;
_sns;
constructor(_awsConfig, _sqs, _sns) {
super();
this._awsConfig = _awsConfig;
this._sqs = _sqs;
this._sns = _sns;
const cfgErrors = BackgroundValidator.validateAwsConfig(_awsConfig);
if (cfgErrors.length) {
ErrorRatchet.throwFormattedErr('Cannot start - invalid AWS config : %j', cfgErrors);
}
}
backgroundManagerName = 'AwsSqsSnsBackgroundManager';
get awsConfig() {
return this._awsConfig;
}
get sqs() {
return this._sqs;
}
get sns() {
return this._sns;
}
async addEntryToQueue(entry, fireStartMessage) {
try {
const wrapped = await this.wrapEntryForInternal(entry);
const rval = wrapped.guid;
const params = {
DelaySeconds: 0,
MessageBody: JSON.stringify(wrapped),
MessageGroupId: entry.type,
QueueUrl: this.awsConfig.queueUrl,
};
Logger.info('Add entry to queue (remote) : %j : Start : %s', params, fireStartMessage);
const result = await this.sqs.send(new SendMessageCommand(params));
if (fireStartMessage) {
const fireResult = await this.fireStartProcessingRequest();
Logger.silly('FireResult : %s', fireResult);
}
Logger.info('Background process %s using message id %s', rval, result.MessageId);
return rval;
}
catch (error) {
Logger.error('Error inserting background entry into SQS queue : %j', error);
throw new Error('Error inserting background entry into SQS queue : ' + error['code'] + ' : ' + error['name']);
}
}
async fireImmediateProcessRequest(entry) {
try {
const wrapped = await this.wrapEntryForInternal(entry);
const rval = wrapped.guid;
Logger.info('Fire immediately (remote) : %j ', entry);
const toWrite = {
type: EpsilonConstants.BACKGROUND_SNS_IMMEDIATE_RUN_FLAG,
backgroundEntry: wrapped,
};
const msg = JSON.stringify(toWrite);
const snsId = await this.writeMessageToSnsTopic(msg);
Logger.debug('Background guid %s Wrote message : %s to SNS : %s', rval, msg, snsId);
return rval;
}
catch (err) {
Logger.error('Failed to fireImmediateProcessRequest : SQS: %s SNS: %s :', this?._awsConfig?.queueUrl, this?._awsConfig?.notificationArn, err, err);
throw new Error('Failed to fireImmediateProcessRequest : : ' + err['code'] + ' : ' + err['name']);
}
}
async fireStartProcessingRequest() {
let rval = null;
try {
Logger.info('Fire start processing request (remote)');
rval = await this.writeMessageToSnsTopic(EpsilonConstants.BACKGROUND_SNS_START_MARKER);
}
catch (err) {
Logger.error('Failed to fireStartProcessingRequest : SQS: %s SNS: %s :', this?._awsConfig?.queueUrl, this?._awsConfig?.notificationArn, err, err);
}
return rval;
}
async fetchApproximateNumberOfQueueEntries() {
let rval = null;
const all = await this.fetchCurrentQueueAttributes();
rval = NumberRatchet.safeNumber(all.Attributes['ApproximateNumberOfMessages']);
return rval;
}
async fetchCurrentQueueAttributes() {
let rval = null;
const req = {
AttributeNames: ['All'],
QueueUrl: this.awsConfig.queueUrl,
};
rval = await this.sqs.send(new GetQueueAttributesCommand(req));
return rval;
}
async writeMessageToSnsTopic(message) {
let rval = null;
const params = {
Message: message,
TopicArn: this.awsConfig.notificationArn,
};
Logger.debug('Writing message to SNS topic : j', params);
const result = await this.sns.send(new PublishCommand(params));
rval = result.MessageId;
return rval;
}
async takeEntryFromBackgroundQueue() {
const rval = [];
const params = {
MaxNumberOfMessages: 1,
QueueUrl: this.awsConfig.queueUrl,
VisibilityTimeout: 300,
WaitTimeSeconds: 0,
};
const message = await this.sqs.send(new ReceiveMessageCommand(params));
if (message && message.Messages && message.Messages.length > 0) {
for (const m of message.Messages) {
try {
const parsedBody = JSON.parse(m.Body);
if (!parsedBody.type) {
Logger.warn('Dropping invalid background entry : %j', parsedBody);
}
else {
rval.push(parsedBody);
}
Logger.debug('Removing message from queue');
const delParams = {
QueueUrl: this.awsConfig.queueUrl,
ReceiptHandle: m.ReceiptHandle,
};
const delResult = await this.sqs.send(new DeleteMessageCommand(delParams));
Logger.silly('Delete result : %j', delResult);
}
catch (err) {
Logger.warn('Error parsing message, dropping : %j', m, err);
}
}
}
else {
Logger.debug('No messages found (likely end of recursion)');
}
return rval;
}
}
//# sourceMappingURL=aws-sqs-sns-background-manager.js.map