UNPKG

@bitblit/ratchet-epsilon-common

Version:

Tiny adapter to simplify building API gateway Lambda APIS

151 lines 6.36 kB
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