Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在MvcAsyncTask中停止可调用_Java_Spring_Spring Mvc_Timeout_Asynccallback - Fatal编程技术网

Java 在MvcAsyncTask中停止可调用

Java 在MvcAsyncTask中停止可调用,java,spring,spring-mvc,timeout,asynccallback,Java,Spring,Spring Mvc,Timeout,Asynccallback,我有一个带有WebAsyncTask的控制器。更进一步,我使用了一个超时回调。 如前所述,我可以选择通知可调用方取消处理。然而,我看不到任何这样做的选择 @Controller public class UserDataProviderController { private static final Logger log = LoggerFactory.getLogger(UserDataProviderController.class.getName()); @Autow

我有一个带有WebAsyncTask的控制器。更进一步,我使用了一个超时回调。 如前所述,我可以选择通知可调用方取消处理。然而,我看不到任何这样做的选择

@Controller
public class UserDataProviderController {

    private static final Logger log = LoggerFactory.getLogger(UserDataProviderController.class.getName());

    @Autowired
    private Collection<UserDataService> dataServices;

       @RequestMapping(value = "/client/{socialSecurityNumber}", method = RequestMethod.GET)
        public @ResponseBody
        WebAsyncTask<ResponseEntity<CustomDataResponse>> process(@PathVariable final String socialSecurityNumber) {

            final Callable<ResponseEntity<CustomDataResponse>> callable = new Callable<ResponseEntity<CustomDataResponse>>() {

                @Override
                public ResponseEntity<CustomDataResponse> call() throws Exception {

                    CustomDataResponse CustomDataResponse = CustomDataResponse.newInstance();

                    // Find user data
                    for(UserDataService dataService:dataServices)
                    {
                        List<? extends DataClient> clients = dataService.findBySsn(socialSecurityNumber);
                        CustomDataResponse.put(dataService.getDataSource(), UserDataConverter.convert(clients));
                    }

                    // test long execution
                    Thread.sleep(4000);

                    log.info("Execution thread continued and shall be terminated:"+Thread.currentThread().getName());


                    HttpHeaders responseHeaders = new HttpHeaders();
                    responseHeaders.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
                    return new ResponseEntity(CustomDataResponse,responseHeaders,HttpStatus.OK);
                }

            };

            final Callable<ResponseEntity<CustomDataResponse>> callableTimeout = new Callable<ResponseEntity<CustomDataResponse>>() {
                @Override
                public ResponseEntity<CustomDataResponse> call() throws Exception {

                    // Error response
                    HttpHeaders responseHeaders = new HttpHeaders();
                    responseHeaders.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
                    return new ResponseEntity("Request has timed out!",responseHeaders,HttpStatus.INTERNAL_SERVER_ERROR);
                }
            };

            WebAsyncTask<ResponseEntity<CustomDataResponse>> task = new WebAsyncTask<>(3000,callable);
            task.onTimeout(callableTimeout);
            return task;
        }
}
非常标准的拦截器:

public class TimeoutCallableProcessingInterceptor extends CallableProcessingInterceptorAdapter {

    @Override
    public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) {

        throw new IllegalStateException("[" + task.getClass().getName() + "] timed out");

    }
}
公共类TimeoutCallableProcessingInterceptor扩展CallableProcessingInterceptorAdapter{
@凌驾
公共对象handleTimeout(NativeWebRequest请求,可调用任务){
抛出新的IllegalStateException(“[”+task.getClass().getName()+“]超时”);
}
}

一切正常,但从控制器调用总是完成的,这是显而易见的,但如何停止那里的处理?

您可以使用
WebAsyncTask
实现超时控制和
Thread
管理来优雅地停止新的异步线程

  • 实现一个
    可调用的
    来运行流程
  • 在此方法中(在不同线程中运行)将当前
    线程
    存储在控制器的局部变量中
  • 实现另一个
    Callable
    来处理超时事件
  • 在此方法中,检索先前存储的
    线程
    ,并调用
    中断()
    方法中断它
  • 同时抛出
    TimeoutException
    以停止控制器进程
  • 在运行的进程中,检查线程是否被
    thread.currentThread().isInterrupted()
    中断,如果是,则回滚引发异常的事务
  • 控制器:

    public WebAsyncTask<ResponseEntity<BookingFileDTO>> confirm(@RequestBody final BookingConfirmationRQDTO bookingConfirmationRQDTO)
            throws AppException,
            ProductException,
            ConfirmationException,
            BeanValidationException {
    
        final Long startTimestamp = System.currentTimeMillis();
        // The compiler obligates to define the local variable shared with the callable as final array
        final Thread[] asyncTaskThread = new Thread[1];
    
        /**
         *  Asynchronous execution of the service's task
         *  Implemented without ThreadPool, we're using Tomcat's ThreadPool
         *  To implement an specific ThreadPool take a look at http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-async-configuration-spring-mvc
         */
        Callable<ResponseEntity<BookingFileDTO>> callableTask = () -> {
    
            //Stores the thread of the newly started asynchronous task
            asyncTaskThread[0] = Thread.currentThread();
    
            log.debug("Running saveBookingFile task at `{}`thread", asyncTaskThread[0].getName());
            BookingFileDTO bookingFileDTO = bookingFileService.saveBookingFile(
                    bookingConfirmationRQDTO,
                    MDC.get(HttpHeader.XB3_TRACE_ID))
                    .getValue();
            if (log.isDebugEnabled()) {
                log.debug("The saveBookingFile task took {} ms",
                        System.currentTimeMillis() - startTimestamp);
            }
            return new ResponseEntity<>(bookingFileDTO, HttpStatus.OK);
        };
    
        /**
         * This method is executed if a timeout occurs
         */
        Callable<ResponseEntity<BookingFileDTO>> callableTimeout = () -> {
    
            String msg = String.format("Timeout detected at %d ms during confirm operation",
                System.currentTimeMillis() - startTimestamp);
            log.error("Timeout detected at {} ms during confirm operation: informing BookingFileService.", msg);
    
            // Informs the service that the time has ran out
            asyncTaskThread[0].interrupt();
    
            // Interrupts the controller call
            throw new TimeoutException(msg);
        };
    
        WebAsyncTask<ResponseEntity<BookingFileDTO>> webAsyncTask = new WebAsyncTask<>(timeoutMillis, callableTask);
        webAsyncTask.onTimeout(callableTimeout);
        log.debug("Timeout set to {} ms", timeoutMillis);
        return webAsyncTask;
    }
    
    public-WebAsyncTask-confirm(@RequestBody-final-BookingConfirmationRQDTO-BookingConfirmationRQDTO)
    抛开欲望,
    产品例外,
    确认例外,
    BeanValidationException{
    最终长startTimestamp=System.currentTimeMillis();
    //编译器有义务将与可调用对象共享的局部变量定义为最终数组
    最终线程[]asyncTaskThread=新线程[1];
    /**
    *异步执行服务的任务
    *在没有线程池的情况下实现,我们使用的是Tomcat的线程池
    *要实现特定的线程池,请查看http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann异步配置springmvc
    */
    可调用可调用任务=()->{
    //存储新启动的异步任务的线程
    asyncTaskThread[0]=Thread.currentThread();
    debug(“在`{}`线程上运行saveBookingFile任务”,asyncTaskThread[0].getName());
    BookingFileDTO BookingFileDTO=bookingFileService.saveBookingFile(
    预订确认书RQDTO,
    MDC.get(HttpHeader.XB3_TRACE_ID))
    .getValue();
    if(log.isDebugEnabled()){
    debug(“saveBookingFile任务花费了{}毫秒”,
    System.currentTimeMillis()-startTimestamp);
    }
    返回新的ResponseEntity(bookingFileDTO,HttpStatus.OK);
    };
    /**
    *如果发生超时,则执行此方法
    */
    可调用callableTimeout=()->{
    String msg=String.format(“确认操作期间在%d毫秒检测到超时”,
    System.currentTimeMillis()-startTimestamp);
    错误(“确认操作期间在{}毫秒检测到超时:通知BookingFileService。”,msg);
    //通知服务时间已过
    asyncTaskThread[0]。中断();
    //中断控制器调用
    抛出新的TimeoutException(msg);
    };
    WebAsyncTask WebAsyncTask=新的WebAsyncTask(timeoutMillis,callableTask);
    webAsyncTask.onTimeout(callableTimeout);
    debug(“超时设置为{}ms”,timeoutMillis);
    返回webAsyncTask;
    }
    
    服务实施:

    /**
     * If the service has been informed that the time has ran out
     * throws an AsyncRequestTimeoutException to roll-back transactions
     */
    private void rollbackOnTimeout() throws TimeoutException {
        if(Thread.currentThread().isInterrupted()) {
            log.error(TIMEOUT_DETECTED_MSG);
            throw new TimeoutException(TIMEOUT_DETECTED_MSG);
        }
    }
    
    @Transactional(rollbackFor = TimeoutException.class, propagation = Propagation.REQUIRES_NEW)
    DTOSimpleWrapper<BookingFileDTO> saveBookingFile(BookingConfirmationRQDTO bookingConfirmationRQDTO, String traceId) {
    
        // Database operations
        // ...
    
        return retValue;
    }
    
    /**
    *如果通知服务时间已过
    *抛出AsyncRequestTimeoutException以回滚事务
    */
    private void rollbackOnTimeout()引发TimeoutException{
    如果(Thread.currentThread().isInterrupted()){
    日志错误(检测到超时消息);
    抛出新的TimeoutException(检测到超时消息);
    }
    }
    @事务性(rollbackFor=TimeoutException.class,传播=propagation.REQUIRES\u NEW)
    DTOSimpleWrapper saveBookingFile(BookingConfirmationRQDTO BookingConfirmationRQDTO,字符串traceId){
    //数据库操作
    // ...
    返回值;
    }
    
    您的意思是需要4秒的可调用进程在3秒后没有停止?是的。基本上,我不希望在睡眠后执行任何代码。可能会重复-@Premek就是这样。您必须手动处理中断,即从数据服务返回结果的可调用程序应检查是否收到中断信号,并在您的情况下,通过发送另一个响应对其采取行动。@Magnamag您的意思是类似于调用:
    Thread.currentThread().interrupt()在CallableTimeout中并在控制器中检查它,有些人认为像'if(Thread.currentThread().isInterrupted()){'我不确定这是正确的方法。。。
    
    /**
     * If the service has been informed that the time has ran out
     * throws an AsyncRequestTimeoutException to roll-back transactions
     */
    private void rollbackOnTimeout() throws TimeoutException {
        if(Thread.currentThread().isInterrupted()) {
            log.error(TIMEOUT_DETECTED_MSG);
            throw new TimeoutException(TIMEOUT_DETECTED_MSG);
        }
    }
    
    @Transactional(rollbackFor = TimeoutException.class, propagation = Propagation.REQUIRES_NEW)
    DTOSimpleWrapper<BookingFileDTO> saveBookingFile(BookingConfirmationRQDTO bookingConfirmationRQDTO, String traceId) {
    
        // Database operations
        // ...
    
        return retValue;
    }