/** * Start concurrent request processing and execute the given task with an * {@link #setTaskExecutor(AsyncTaskExecutor) AsyncTaskExecutor}. The result * from the task execution is saved and the request dispatched in order to * resume processing of that result. If the task raises an Exception then * the saved result will be the raised Exception. * @param callable a unit of work to be executed asynchronously * @param processingContext additional context to save that can be accessed * via {@link #getConcurrentResultContext()} * @throws Exception if concurrent processing failed to start * @see #getConcurrentResult() * @see #getConcurrentResultContext() */ @SuppressWarnings({"unchecked", "rawtypes"}) public void startCallableProcessing(Callable<?> callable, Object... processingContext) throws Exception { Assert.notNull(callable, "Callable must not be null"); startCallableProcessing(new WebAsyncTask(callable), processingContext); }
Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null"); Long timeout = webAsyncTask.getTimeout(); if (timeout != null) { this.asyncWebRequest.setTimeout(timeout); AsyncTaskExecutor executor = webAsyncTask.getExecutor(); if (executor != null) { this.taskExecutor = executor; interceptors.add(webAsyncTask.getInterceptor()); interceptors.addAll(this.callableInterceptors.values()); interceptors.add(timeoutCallableInterceptor); final Callable<?> callable = webAsyncTask.getCallable(); final CallableInterceptorChain interceptorChain = new CallableInterceptorChain(interceptors);
@Test public void startCallableProcessingTimeoutAndResumeThroughCallback() throws Exception { StubCallable callable = new StubCallable(); WebAsyncTask<Object> webAsyncTask = new WebAsyncTask<>(callable); webAsyncTask.onTimeout(new Callable<Object>() { @Override public Object call() throws Exception { return 7; } }); this.asyncManager.startCallableProcessing(webAsyncTask); this.asyncWebRequest.onTimeout(ASYNC_EVENT); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(7, this.asyncManager.getConcurrentResult()); assertEquals("/test", ((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()); }
@Test public void startCallableProcessingErrorAndResumeThroughCallback() throws Exception { StubCallable callable = new StubCallable(); WebAsyncTask<Object> webAsyncTask = new WebAsyncTask<>(callable); webAsyncTask.onError(new Callable<Object>() { @Override public Object call() throws Exception { return 7; } }); this.asyncManager.startCallableProcessing(webAsyncTask); Exception e = new Exception(); AsyncEvent event = new AsyncEvent(new MockAsyncContext(this.servletRequest, this.servletResponse), e); this.asyncWebRequest.onError(event); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(7, this.asyncManager.getConcurrentResult()); assertEquals("/test", ((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()); }
@RequestMapping("/webAsyncTask") public WebAsyncTask<String> webAsyncTask() { log.info("外部线程:" + Thread.currentThread().getName()); WebAsyncTask<String> result = new WebAsyncTask<String>(60*1000L, new Callable<String>() { @Override public String call() throws Exception { log.info("内部线程:" + Thread.currentThread().getName()); return "WebAsyncTask!!!"; } }); result.onTimeout(new Callable<String>() { @Override public String call() throws Exception { // TODO Auto-generated method stub return "WebAsyncTask超时!!!"; } }); result.onCompletion(new Runnable() { @Override public void run() { //超时后 也会执行此方法 log.info("WebAsyncTask执行结束"); } }); return result; } }
@Around("anyControllerOrRestControllerWithPublicWebAsyncTaskMethod()") public Object wrapWebAsyncTaskWithCorrelationId(ProceedingJoinPoint pjp) throws Throwable { final WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) pjp.proceed(); TraceContext currentSpan = this.tracing.currentTraceContext().get(); if (currentSpan == null) { return webAsyncTask; } try { if (log.isDebugEnabled()) { log.debug("Wrapping callable with span [" + currentSpan + "]"); } Field callableField = WebAsyncTask.class.getDeclaredField("callable"); callableField.setAccessible(true); callableField.set(webAsyncTask, new TraceCallable<>(this.tracing, this.spanNamer, webAsyncTask.getCallable())); } catch (NoSuchFieldException ex) { log.warn("Cannot wrap webAsyncTask's callable with TraceCallable", ex); } return webAsyncTask; }
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { mavContainer.setRequestHandled(true); return; } WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue; if (this.beanFactory != null) { webAsyncTask.setBeanFactory(this.beanFactory); } WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer); }
@Around("anyControllerOrRestControllerWithPublicWebAsyncTaskMethod()") public Object tracePublicWebAsyncTaskMethods(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { final WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) proceedingJoinPoint.proceed(); Field callableField = WebAsyncTask.class.getDeclaredField("callable"); callableField.setAccessible(true); // do not create span (there is always server span) just pass it to new thread. callableField .set(webAsyncTask, new TracedCallable<>(webAsyncTask.getCallable(), tracer)); return webAsyncTask; } }
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { mavContainer.setRequestHandled(true); return; } WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue; if (this.beanFactory != null) { webAsyncTask.setBeanFactory(this.beanFactory); } WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer); }
Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null"); Long timeout = webAsyncTask.getTimeout(); if (timeout != null) { this.asyncWebRequest.setTimeout(timeout); AsyncTaskExecutor executor = webAsyncTask.getExecutor(); if (executor != null) { this.taskExecutor = executor; interceptors.add(webAsyncTask.getInterceptor()); interceptors.addAll(this.callableInterceptors.values()); interceptors.add(timeoutCallableInterceptor); final Callable<?> callable = webAsyncTask.getCallable(); final CallableInterceptorChain interceptorChain = new CallableInterceptorChain(interceptors);
/** * Start concurrent request processing and execute the given task with an * {@link #setTaskExecutor(AsyncTaskExecutor) AsyncTaskExecutor}. The result * from the task execution is saved and the request dispatched in order to * resume processing of that result. If the task raises an Exception then * the saved result will be the raised Exception. * @param callable a unit of work to be executed asynchronously * @param processingContext additional context to save that can be accessed * via {@link #getConcurrentResultContext()} * @throws Exception if concurrent processing failed to start * @see #getConcurrentResult() * @see #getConcurrentResultContext() */ @SuppressWarnings({"unchecked", "rawtypes"}) public void startCallableProcessing(Callable<?> callable, Object... processingContext) throws Exception { Assert.notNull(callable, "Callable must not be null"); startCallableProcessing(new WebAsyncTask(callable), processingContext); }
@RequestMapping(value = "/generateVersion", method = RequestMethod.POST) @ResponseBody public WebAsyncTask<String> generateVersion(String jobId) { if (!hasPermission(Integer.parseInt(jobId), JOB)) { return new WebAsyncTask<>(() -> ERROR_MSG); } WebAsyncTask<String> asyncTask = new WebAsyncTask<>(HeraGlobalEnvironment.getRequestTimeout(), () -> workClient.generateActionFromWeb(JobExecuteKind.ExecuteKind.ManualKind, jobId)); asyncTask.onTimeout(() -> "版本生成时间较长,请耐心等待下"); return asyncTask; }
@Around("anyControllerOrRestControllerWithPublicWebAsyncTaskMethod()") public Object wrapWebAsyncTaskWithCorrelationId(ProceedingJoinPoint pjp) throws Throwable { final WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) pjp.proceed(); TraceContext currentSpan = this.tracing.currentTraceContext().get(); if (currentSpan == null) { return webAsyncTask; } try { if (log.isDebugEnabled()) { log.debug("Wrapping callable with span [" + currentSpan + "]"); } Field callableField = WebAsyncTask.class.getDeclaredField("callable"); callableField.setAccessible(true); callableField.set(webAsyncTask, new TraceCallable<>(this.tracing, this.spanNamer, webAsyncTask.getCallable())); } catch (NoSuchFieldException ex) { log.warn("Cannot wrap webAsyncTask's callable with TraceCallable", ex); } return webAsyncTask; }
@Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { mavContainer.setRequestHandled(true); return; } WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue; webAsyncTask.setBeanFactory(this.beanFactory); WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer); }
Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null"); Long timeout = webAsyncTask.getTimeout(); if (timeout != null) { this.asyncWebRequest.setTimeout(timeout); AsyncTaskExecutor executor = webAsyncTask.getExecutor(); if (executor != null) { this.taskExecutor = executor; interceptors.add(webAsyncTask.getInterceptor()); interceptors.addAll(this.callableInterceptors.values()); interceptors.add(timeoutCallableInterceptor); final Callable<?> callable = webAsyncTask.getCallable(); final CallableInterceptorChain interceptorChain = new CallableInterceptorChain(interceptors);
@SuppressWarnings("unchecked") @Test public void startCallableProcessingWithAsyncTask() throws Exception { AsyncTaskExecutor executor = mock(AsyncTaskExecutor.class); given(this.asyncWebRequest.getNativeRequest(HttpServletRequest.class)).willReturn(this.servletRequest); WebAsyncTask<Object> asyncTask = new WebAsyncTask<>(1000L, executor, mock(Callable.class)); this.asyncManager.startCallableProcessing(asyncTask); verify(executor).submit((Runnable) notNull()); verify(this.asyncWebRequest).setTimeout(1000L); verify(this.asyncWebRequest).addTimeoutHandler(any(Runnable.class)); verify(this.asyncWebRequest).addErrorHandler(any(Consumer.class)); verify(this.asyncWebRequest).addCompletionHandler(any(Runnable.class)); verify(this.asyncWebRequest).startAsync(); }
@RequestMapping(value = "/generateAllVersion", method = RequestMethod.GET) @ResponseBody public WebAsyncTask<String> generateAllVersion() { if (!isAdmin(getOwner())) { return new WebAsyncTask<>(() -> ERROR_MSG); } WebAsyncTask<String> asyncTask = new WebAsyncTask<>(HeraGlobalEnvironment.getRequestTimeout(), () -> workClient.generateActionFromWeb(JobExecuteKind.ExecuteKind.ManualKind, Constants.ALL_JOB_ID)); asyncTask.onTimeout(() -> "全量版本生成时间较长,请耐心等待下"); return asyncTask; }
Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null"); Long timeout = webAsyncTask.getTimeout(); if (timeout != null) { this.asyncWebRequest.setTimeout(timeout); AsyncTaskExecutor executor = webAsyncTask.getExecutor(); if (executor != null) { this.taskExecutor = executor; interceptors.add(webAsyncTask.getInterceptor()); interceptors.addAll(this.callableInterceptors.values()); interceptors.add(timeoutCallableInterceptor); final Callable<?> callable = webAsyncTask.getCallable(); final CallableInterceptorChain interceptorChain = new CallableInterceptorChain(interceptors);
/** * 取消执行脚本 * * @param id * @return */ @RequestMapping(value = "/cancelJob", method = RequestMethod.GET) @ResponseBody public WebAsyncTask<String> cancelJob(String id) { return new WebAsyncTask<>(3000, () -> workClient.cancelJobFromWeb(JobExecuteKind.ExecuteKind.DebugKind, id)); }
@RequestMapping(value = "/homePage/getAllWorkInfo", method = RequestMethod.GET) @ResponseBody public WebAsyncTask getAllWorkInfo() { WebAsyncTask webAsyncTask = new WebAsyncTask<>(HeraGlobalEnvironment.getRequestTimeout(), () -> workClient.getAllWorkInfo()); webAsyncTask.onTimeout(() -> { ErrorLog.error("获取work信息超时"); return null; }); return webAsyncTask; }