Я использую StreamingResponseBody для записи в выходной поток. Однако при нагрузочных тестах я вижу несколько исключений:
at org.springframework.boot.actuate.trace.http.HttpExchangeTracer$FilteredTraceableResponse.includedHeader(HttpExchangeTracer.java:167)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
"java.lang.NullPointerException
at org.springframework.boot.actuate.trace.http.HttpExchangeTracer.lambda$getHeadersIfIncluded$1(HttpExchangeTracer.java:101)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)".
Вот код: я что-то здесь упускаю?
@GetMapping(value = ID_PATH_PARAM_MAPPING + PDF_PATH)
@ApiOperation(value = "Get", notes = "Fetch pdf")
@ApiImplicitParams({
@ApiImplicitParam(name = ID_PATH_PARAM, value = "Id", required = true, dataType = "string", paramType = "path")})
public ResponseEntity<StreamingResponseBody> getSalePdfByToken(@PathVariable(ID_PATH_PARAM) String eSaleId) {
PdfDomain pdfResponse = service.getPdf(Id);
StreamingResponseBody responseBody = getStreamingResponseBody(pdfResponse);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_PDF)
.body(responseBody);
}
private StreamingResponseBody getStreamingResponseBody(PdfDomain pdfResponse) {
return outputStream -> {
int numberOfBytesToWrite;
byte[] data = new byte[scsAppConfig.getChunkSize()];
while ((numberOfBytesToWrite = pdfResponse.getResponse().read(data, 0, data.length)) != -1) {
log.debug("action=getSalePdfByToken; message=writing bytes..;");
outputStream.write(data, 0, numberOfBytesToWrite);
}
pdfResponse.getResponse().close();
};
}
Мой асин c config
@Configuration
@ConfigurationProperties(prefix = "config.async")
@EnableAsync
@Log4j2
@Getter
@Setter
public class AsyncConfig implements AsyncConfigurer {
private final String THREAD_NAME_PREFIX = "Async_Service_Pool";
private int corePoolSize = 10;
private int maxPoolSize = 25;
private int queueCapacity = 100;
private long defaultTimeOut = 20000;
@Bean(name = "asyncTaskExecutor")
public AsyncTaskExecutor asyncTaskExecutor(AsyncDecorator asyncDecorator) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
executor.setCorePoolSize(getCorePoolSize());
executor.setMaxPoolSize(getMaxPoolSize());
executor.setQueueCapacity(getQueueCapacity());
executor.setTaskDecorator(asyncDecorator);
executor.initialize();
log.info("AsyncConfig; action=asyncTaskExecutor; state=start; message=\"started executor\"; threadNamePrefix={}; corePoolSize={}; maxPoolSize={}; queueCapacity={}\";",
executor.getThreadNamePrefix(), corePoolSize, maxPoolSize, queueCapacity);
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
@Bean
public WebMvcConfigurer webMvcConfigurerConfigurer(AsyncTaskExecutor taskExecutor, CallableProcessingInterceptor callableProcessingInterceptor) {
return new WebMvcConfigurer() {
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(getDefaultTimeOut()).setTaskExecutor(taskExecutor);
configurer.registerCallableInterceptors(callableProcessingInterceptor);
WebMvcConfigurer.super.configureAsyncSupport(configurer);
}
};
}
@Bean
public CallableProcessingInterceptor callableProcessingInterceptor() {
return new TimeoutCallableProcessingInterceptor() {
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
log.error("action=handleTimeout; state=error; message=\"timeout occurred\";");
return super.handleTimeout(request, task);
}
};
}
}