Skip to content

Commit

Permalink
fix(@aws-sdk/client-sns): do not crash if there is no current transac…
Browse files Browse the repository at this point in the history
…tion (#4168)

Before this change, instrumentation of `@aws-sdk/client-sns` would *crash*
if there wasn't a current transaction.

Fixes: #4138
  • Loading branch information
trentm committed Aug 1, 2024
1 parent 2782648 commit c77c425
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 26 deletions.
46 changes: 24 additions & 22 deletions lib/instrumentation/modules/@aws-sdk/client-sns.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,30 @@ function snsMiddlewareFactory(client, agent) {
const targetId =
input && (input.TopicArn || input.TargetArn || input.PhoneNumber);

// Though our spec only mentions a 10-message-attribute limit for *SQS*, we'll
// do the same limit here, because
// https://docs.aws.amazon.com/sns/latest/dg/sns-message-attributes.html
// mentions the 10-message-attribute limit for SQS subscriptions.
input.MessageAttributes = input.MessageAttributes || {};
const attributesCount = Object.keys(input.MessageAttributes).length;

if (attributesCount + 2 > MAX_SNS_MESSAGE_ATTRIBUTES) {
log.warn(
'cannot propagate trace-context with SNS message to %s, too many MessageAttributes',
targetId,
);
} else {
parentSpan.propagateTraceContextHeaders(
input.MessageAttributes,
function (msgAttrs, name, value) {
if (name.startsWith('elastic-')) {
return;
}
msgAttrs[name] = { DataType: 'String', StringValue: value };
},
);
if (parentSpan) {
// Though our spec only mentions a 10-message-attribute limit for *SQS*, we'll
// do the same limit here, because
// https://docs.aws.amazon.com/sns/latest/dg/sns-message-attributes.html
// mentions the 10-message-attribute limit for SQS subscriptions.
input.MessageAttributes = input.MessageAttributes || {};
const attributesCount = Object.keys(input.MessageAttributes).length;

if (attributesCount + 2 > MAX_SNS_MESSAGE_ATTRIBUTES) {
log.warn(
'cannot propagate trace-context with SNS message to %s, too many MessageAttributes',
targetId,
);
} else {
parentSpan.propagateTraceContextHeaders(
input.MessageAttributes,
function (msgAttrs, name, value) {
if (name.startsWith('elastic-')) {
return;
}
msgAttrs[name] = { DataType: 'String', StringValue: value };
},
);
}
}

// Ensure there is a span from the wrapped `client.send()`.
Expand Down
18 changes: 18 additions & 0 deletions test/instrumentation/modules/@aws-sdk/client-sns.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,24 @@ const testFixtures = [
t.equal(spans.length, 0, 'all spans accounted for');
},
},

{
name: 'use-client-sns.js without a created transaction to ensure does not crash',
script: 'fixtures/use-client-sns.js',
cwd: __dirname,
env: {
AWS_ACCESS_KEY_ID: 'fake',
AWS_SECRET_ACCESS_KEY: 'fake',
TEST_ENDPOINT: endpoint,
TEST_REGION: 'us-east-2',
TEST_NO_TRANSACTION: 'true',
},
versionRanges: {
node: '>=14',
},
verbose: true,
},

{
name: '@aws-sdk/client-sns ESM',
script: 'fixtures/use-client-sns.mjs',
Expand Down
18 changes: 14 additions & 4 deletions test/instrumentation/modules/@aws-sdk/fixtures/use-client-sns.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ function main() {
const endpoint = process.env.TEST_ENDPOINT || null;
const topicName =
process.env.TEST_TOPIC_NAME || TEST_TOPIC_NAME_PREFIX + getTimestamp();
// `TEST_NO_TRANSACTION=true` can be used to disable the creating of a
// current transaction for SNS calls; useful only for testing.
const noTransaction = process.env.TEST_NO_TRANSACTION === 'true';

// Guard against any topic name being used because we will be publishing
// messages in it, and potentially *deleting* the topic.
Expand All @@ -240,18 +243,25 @@ function main() {
});

// Ensure an APM transaction so spans can happen.
const tx = apm.startTransaction('manual');
let tx = null;
if (!noTransaction) {
tx = apm.startTransaction('manual');
}

useClientSNS(snsClient, topicName).then(
function () {
tx.end();
if (tx) {
tx.end();
}
snsClient.destroy();
process.exitCode = 0;
},
function (err) {
apm.logger.error(err, 'useClientSNS rejected');
tx.setOutcome('failure');
tx.end();
if (tx) {
tx.setOutcome('failure');
tx.end();
}
snsClient.destroy();
process.exitCode = 1;
},
Expand Down

0 comments on commit c77c425

Please sign in to comment.