@message-queue-toolkit/sns
Version:
SNS adapter for message-queue-toolkit
126 lines • 5.99 kB
JavaScript
import { AbstractSqsConsumer, deleteSqs } from '@message-queue-toolkit/sqs';
import { deleteSnsSqs, initSnsSqs } from "../utils/snsInitter.js";
import { readSnsMessage } from "../utils/snsMessageReader.js";
export class AbstractSnsSqsConsumer extends AbstractSqsConsumer {
subscriptionConfig;
snsClient;
stsClient;
/**
* Tracks whether resources (SNS topic, SQS queue, subscription) are ready.
* In non-blocking polling mode, this may be false initially and become true
* when the onResourcesReady callback fires.
*/
resourcesReady = false;
/**
* Tracks whether start() has been called but consumers couldn't be started
* because resources weren't ready yet. When resources become ready and this
* is true, consumers will be started automatically.
*/
startRequested = false;
// @ts-expect-error
topicArn;
// @ts-expect-error
subscriptionArn;
constructor(dependencies, options, executionContext) {
super(dependencies, {
...options,
}, executionContext);
this.subscriptionConfig = options.subscriptionConfig;
this.snsClient = dependencies.snsClient;
this.stsClient = dependencies.stsClient;
}
async init() {
if (this.deletionConfig && this.creationConfig && this.subscriptionConfig) {
await deleteSnsSqs(this.sqsClient, this.snsClient, this.stsClient, this.deletionConfig, this.creationConfig.queue, this.creationConfig.topic, this.subscriptionConfig, undefined, this.locatorConfig);
}
else if (this.deletionConfig && this.creationConfig) {
await deleteSqs(this.sqsClient, this.deletionConfig, this.creationConfig);
}
const initSnsSqsResult = await initSnsSqs(this.sqsClient, this.snsClient, this.stsClient, this.locatorConfig, this.creationConfig, this.subscriptionConfig, {
logger: this.logger,
// This callback is only invoked in non-blocking mode when resources were NOT
// immediately available. It will NOT be called if resourcesReady is true.
onResourcesReady: (result) => {
// Update values that were empty when resourcesReady was false
this.topicArn = result.topicArn;
this.queueUrl = result.queueUrl;
this.subscriptionArn = result.subscriptionArn;
this.queueName = result.queueName;
this.resourcesReady = true;
// Initialize DLQ now that resources are ready (this is mutually exclusive
// with the synchronous initDeadLetterQueue call below)
this.initDeadLetterQueue()
.catch((err) => {
this.logger.error({
message: 'Failed to initialize dead letter queue after resources became ready',
error: err,
});
})
.then(() => {
// If start() was called while resources weren't ready, start consumers now
if (this.startRequested) {
this.logger.info({
message: 'Resources now ready, starting consumers',
queueName: this.queueName,
topicArn: this.topicArn,
});
return this.startConsumers();
}
})
.catch((err) => {
this.logger.error({
message: 'Failed to start consumers after resources became ready',
error: err,
});
});
},
});
// Always assign topicArn and queueName (always valid in both blocking and non-blocking modes)
this.topicArn = initSnsSqsResult.topicArn;
this.queueName = initSnsSqsResult.queueName;
this.resourcesReady = initSnsSqsResult.resourcesReady;
// Only assign queueUrl and subscriptionArn if resources are ready,
// or if they have valid values (non-blocking mode with locatorConfig provides valid values)
if (initSnsSqsResult.resourcesReady || initSnsSqsResult.queueUrl) {
this.queueUrl = initSnsSqsResult.queueUrl;
this.subscriptionArn = initSnsSqsResult.subscriptionArn;
}
// Only initialize DLQ if resources are ready and queueUrl is available
if (initSnsSqsResult.resourcesReady && initSnsSqsResult.queueUrl) {
await this.initDeadLetterQueue();
}
}
/**
* Starts the consumer. In non-blocking polling mode, if resources aren't ready yet,
* this method will return immediately and consumers will start automatically once
* resources become available.
*/
async start() {
await this.init();
if (!this.resourcesReady) {
// Resources not ready yet (non-blocking polling mode), mark that start was requested.
// Consumers will be started automatically when onResourcesReady callback fires.
this.startRequested = true;
this.logger.info({
message: 'Start requested but resources not ready yet, will start when resources become available',
queueName: this.queueName,
topicArn: this.topicArn,
});
return;
}
// Resources are ready, start consumers immediately
await this.startConsumers();
}
resolveMessage(message) {
const result = readSnsMessage(message, this.errorResolver);
if (result.result) {
return result;
}
// if it not an SNS message, then it is a SQS message
return super.resolveMessage(message);
}
resolveSchema(messagePayload) {
return this._messageSchemaContainer.resolveSchema(messagePayload);
}
}
//# sourceMappingURL=AbstractSnsSqsConsumer.js.map