Aws-xray-sdk-node: Preserve tracing using sqs-consumer.

Created on 9 May 2021  路  4Comments  路  Source: aws/aws-xray-sdk-node

I have two microservices namely user-service and notification-service, whenever user sign-up to user-service. the message will add to sqs queue with AWSTraceHeader, now from notification-service sqs-consumer will poll and pass that message to handleMessage callback function and send an email to enduser using SES.

I can able to trace the process till, user-service ---> sqs queue, but how can traceId entire flow like user-service->queue->notification-service->ses. I tried the following code

handleMessage: async (message: SQS.Message) => {
    const segment = AWSXRay.getSegment()
    if(segment){
      segment.trace_id = message.Attributes?.AWSTraceHeader
    }

    await wiring.sqsService.handleMessage(message);
  }

but got the error like below
Property 'trace_id' does not exist on type 'Segment | Subsegment'. Property 'trace_id' does not exist on type 'Subsegment'.

How can I trace the entire process?

question

All 4 comments

Hello,

In order to set the trace ID of a segment as you want to here, you need to access the trace_id field on the parent Segment, not on the subsegment as you're attempting to now. The AWSXRay.getSegment() API is a bit of a misnomer, it actually gets the current segment OR subsegment in progress. To always retrieve the top-level segment from the subsegment, do:

const entity = AWSXRay.getSegment();

// If entity is a segment, retrieve trace ID directly, otherwise get trace ID from parent segment
const traceId = entity.trace_id ? entity.trace_id : entity.segment.trace_id;

The only problem with this is that you may have several traces representing SQS messages that are "Fanning in" to a single trace on the consumer side. This is the issue that is tracked in #208, so we will not address it here to avoid duplication.

Thanks for your reply, one small question, if I close the segment after handleMessage like below

handleMessage: async (message: SQS.Message) => {
    const segment = AWSXRay.getSegment()
    if(segment){
      segment.trace_id = message.Attributes?.AWSTraceHeader
    }

    await wiring.sqsService.handleMessage(message);
    segment.closeSegment()
  }

Do I need to open the new segment again, because openSegment() invoked like below.

const segment = new AWSXRay.Segment(this.appName);
    const ns = AWSXRay.getNamespace();
    ns.run(() => {
      AWSXRay.setSegment(segment);
      this.sqsConsumer.start();
    });

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs in next 7 days. Thank you for your contributions.

@hariharasudhan-nineleaps I'm not sure I entirely understand your question. Each call to open a segment should have a corresponding call to close the segment later in execution, no matter what (e.g. in a finally block).

Was this page helpful?
0 / 5 - 0 ratings