0

X-Ray is integrated into my service and everything works fine when some endpoints are triggered from other services.

The Spring Batch job is used to process some data and push some part of it to SNS topic. This job is launched via SimpleJobLauncher.

The issue is that during the pushing to SNS from my Spring Batch the following exception is thrown: SegmentNotFoundException: No segment in progress .

Based on the documentation it looks like I need to pass the trace ID to the job: https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-java-multithreading.html

Does anyone know what is the best way to integrate X-Ray with Spring Batch? And what would be the cleanest solution?

1 Answers1

0

I solved this issue in the following way:

I've passed name, trace id and parent id to my job via job parameters while launching the job:

Entity segment = AWSXRay.getGlobalRecorder().getTraceEntity();

asyncJobLauncher.run(
      myJob,
      new JobParametersBuilder()
        .addLong(JOB_UNIQUENESS_KEY, System.nanoTime())
        .addString(X_RAY_NAME_ID_KEY, segment.getName())
        .addString(X_RAY_TRACE_ID_KEY, segment.getTraceId().toString())
        .addString(X_RAY_PARENT_ID_KEY, segment.getParentId())
        .toJobParameters()
    );

I've implemented the job listener to create a new X-Ray segment while starting a job:

@Slf4j
@Component
@RequiredArgsConstructor
public class XRayJobListener implements JobExecutionListener {

  @Value("${spring.application.name}")
  private String appName;

  @Override
  public void beforeJob(@NonNull JobExecution jobExecution) {

    AWSXRayRecorder recorder = AWSXRay.getGlobalRecorder();

    String name = Objects.requireNonNullElse(
      jobExecution.getJobParameters().getString(X_RAY_NAME_ID_KEY),
      appName
    );

    Optional<String> traceIdOpt =
      Optional.ofNullable(jobExecution.getJobParameters().getString(X_RAY_TRACE_ID_KEY));

    TraceID traceID =
      traceIdOpt
        .map(TraceID::fromString)
        .orElseGet(TraceID::create);

    String parentId = jobExecution.getJobParameters().getString(X_RAY_PARENT_ID_KEY);

    recorder.beginSegment(name, traceID, parentId);
  }

  @Override
  public void afterJob(@NonNull JobExecution jobExecution) {
    AWSXRay.getGlobalRecorder().endSegment();
  }
}

And this listener is added to the configuration of my job:

  @Bean
  public Job myJob(
    JobBuilderFactory jobBuilderFactory,
    Step myStep1,
    Step myStep2,
    XRayJobListener xRayJobListener
  ) {
    return
      jobBuilderFactory
        .get("myJob")
        .incrementer(new RunIdIncrementer())
        .listener(xRayJobListener)
        .start(myStep1)
        .next(myStep2)
        .build();
  }