Spring Boot에서 StreamingResponseBody를 사용하여 대용량 파일을 다운로드하는 비동기 시간 초과
먼저 메모리에 저장하지 않고 대용량 파일 스트리밍을 다운로드할 수 있는 REST 서비스를 노출하려고 합니다.또한 두 명의 사용자가 동시에 이 URL을 호출할 경우 비동기 호출을 지원하기 위해 이 URL이 둘 다 다운로드할 수 있어야 합니다.응용 프로그램은 Spring Boot로 설정됩니다.
컨트롤러에 대한 내용은 다음과 같습니다.
@RestController
public class MyController {
private MyService service;
@Autowired
public MyController(MyService service) {
this.service = service;
}
@RequestMapping(
value = "download",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<StreamingResponseBody> downloadAsync() throws IOException {
StreamingResponseBody responseBody = outputStream -> {
service.download(outputStream);
outputStream.close();
};
return ResponseEntity.ok(responseBody);
}
}
다음은 서비스에 대한 내용입니다(다운로드 URL은 이 동작을 테스트하기 위한 샘플일 뿐입니다).
@Service
public class MyService {
private RestTemplate restTemplate;
@Autowired
public MyService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public void download(OutputStream outputStream) {
ResponseExtractor<Void> responseExtractor = clientHttpResponse -> {
InputStream inputStream = clientHttpResponse.getBody();
StreamUtils.copy(inputStream, outputStream);
return null;
};
restTemplate.execute("http://download.thinkbroadband.com/1GB.zip",
HttpMethod.GET,
clientHttpRequest -> {},
responseExtractor);
}
}
인application.yml
다른 것들 중에서도, 저는 이런 특성들을 가지고 있고, 전혀 화려하지 않습니다.
server:
port: 9999
context-path: /rest
다음은 JavaConfig 파일입니다.
@Configuration
public class ApplicationConfig {
@Bean
public RestTemplate restTemplate() {
ClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault());
RestTemplate restTemplate = new RestTemplate(requestFactory);
restTemplate.setErrorHandler(new ClientErrorHandler());
return restTemplate;
}
}
이 끝점을 호출할 때localhost:9999/rest/download
다운로드가 시작되고 일부 MB가 다운로드되지만 시간이 지나면 중지되고 콘솔에 다음과 같이 표시됩니다.
2017-03-18 17:11:54.808 INFO --- [nio-9999-exec-1] o.a.c.c.C.[.[.[/rest] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-03-18 17:11:54.811 INFO --- [nio-9999-exec-1] o.s.w.s.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2017-03-18 17:11:54.895 INFO --- [nio-9999-exec-1] o.s.w.s.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 84 ms
2017-03-18 17:12:25.334 ERROR --- [nio-9999-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Async timeout for GET [/rest/download]
2017-03-18 17:12:25.335 WARN --- [nio-9999-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.context.request.async.AsyncRequestTimeoutException
2017-03-18 17:12:25.366 INFO --- [nio-9999-exec-2] o.a.c.c.CoyoteAdapter : Encountered a non-recycled response and recycled it forcedly.
org.apache.catalina.connector.CoyoteAdapter$RecycleRequiredException: null
at org.apache.catalina.connector.CoyoteAdapter.checkRecycled(CoyoteAdapter.java:494) [tomcat-embed-core-8.5.11.jar:8.5.11]
at org.apache.coyote.http11.Http11Processor.recycle(Http11Processor.java:1627) [tomcat-embed-core-8.5.11.jar:8.5.11]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.release(AbstractProtocol.java:977) [tomcat-embed-core-8.5.11.jar:8.5.11]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:869) [tomcat-embed-core-8.5.11.jar:8.5.11]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434) [tomcat-embed-core-8.5.11.jar:8.5.11]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.11.jar:8.5.11]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_60]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_60]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.11.jar:8.5.11]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_60]
누구 좀 도와주시겠어요?잘 부탁드립니다.
Spring-Boot를 사용하여 이 문제가 발생하는 경우 다음 속성을 더 높은 값으로 설정하면 됩니다. 예를 들어 다음과 같습니다.
spring:
mvc:
async:
request-timeout: 3600000
또는
spring.mvc.async.request-timeout = 3600000
비동기 작업 실행기에서 시간 초과 문제가 발생한 것 같습니다.원하는 시간 초과(및 기타 설정)를 구성할 수 있습니다.WebMvcConfigurerAdapter
이 코드는 이 문제를 해결하는 데 도움이 될 것입니다.줄임표(...)를 원하는 값으로 바꾸십시오.
이 예제는 또한 특별한 처리가 필요한 경우 시간 초과 시 호출되는 인터셉트를 등록합니다.
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
@Override
@Bean(name = "taskExecutor")
public AsyncTaskExecutor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(...);
executor.setMaxPoolSize(...);
executor.setQueueCapacity(...);
executor.setThreadNamePrefix(...);
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
/** Configure async support for Spring MVC. */
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(AsyncTaskExecutor taskExecutor, CallableProcessingInterceptor callableProcessingInterceptor) {
return new WebMvcConfigurerAdapter() {
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(...)
.setTaskExecutor(taskExecutor);
configurer.registerCallableInterceptors(callableProcessingInterceptor);
super.configureAsyncSupport(configurer);
}
};
}
@Bean
public CallableProcessingInterceptor callableProcessingInterceptor() {
return new TimeoutCallableProcessingInterceptor() {
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
log.error("timeout!");
return super.handleTimeout(request, task);
}
};
}
}
언급URL : https://stackoverflow.com/questions/42877498/async-timeout-downloading-a-large-file-using-streamingresponsebody-on-spring-boo
'programing' 카테고리의 다른 글
Vuex에서 404 페이지 표시로 Axios 오류 포착 (0) | 2023.06.20 |
---|---|
24시간을 12시간으로 변환하고 오전/오후 표시 Oracle SQL (0) | 2023.06.20 |
VBA - 날짜로 변환 (0) | 2023.06.20 |
ASP.NET에서 영구 쿠키를 만들려면 어떻게 해야 합니까? (0) | 2023.06.20 |
Gitrebase, '로컬' 및 '원격' 추적 (0) | 2023.06.20 |