Passing segment context between threads in a multithreaded application - AWS X-Ray

Passing segment context between threads in a multithreaded application

When you create a new thread in your application, the AWSXRayRecorder doesn't maintain a reference to the current segment or subsegment Entity. If you use an instrumented client in the new thread, the SDK tries to write to a segment that doesn't exist, causing a SegmentNotFoundException.

To avoid throwing exceptions during development, you can configure the recorder with a ContextMissingStrategy that tells it to log an error instead. You can configure the strategy in code with SetContextMissingStrategy, or configure equivalent options with an environment variable or system property.

One way to address the error is to use a new segment by calling beginSegment when you start the thread and endSegment when you close it. This works if you are instrumenting code that doesn't run in response to an HTTP request, like code that runs when your application starts.

If you use multiple threads to handle incoming requests, you can pass the current segment or subsegment to the new thread and provide it to the global recorder. This ensures that the information recorded within the new thread is associated with the same segment as the rest of the information recorded about that request. Once the segment is available in the new thread, you can execute any runnable with access to that segment's context using the segment.run(() -> { ... }) method.

See Using instrumented clients in worker threads for an example.

Using X-Ray with Asynchronous Programming

The X-Ray SDK for Java can be used in asynchronous Java programs with SegmentContextExecutors]. The SegmentContextExecutor implements the Executor interface, which means it can be passed into all asynchronous operations of a CompletableFuture]. This ensures that any asynchronous operations will be executed with the correct segment in its context.

Example App.java: Passing SegmentContextExecutor to CompletableFuture

DynamoDbAsyncClient client = DynamoDbAsyncClient.create(); AWSXRay.beginSegment(); // ... client.getItem(request).thenComposeAsync(response -> { // If we did not provide the segment context executor, this request would not be traced correctly. return client.getItem(request2); }, SegmentContextExecutors.newSegmentContextExecutor());