Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServletRequestAttributes becomes inactive before child thread finishes its task [SPR-15580] #20139

Open
spring-issuemaster opened this issue May 23, 2017 · 0 comments

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented May 23, 2017

Yongqin Xu opened SPR-15580 and commented

I am using SpringBoot 1.5.2 release. I have an asynchronous REST call that spawns separate java thread to finish a long running job. i use Postman to send POST request to async REST api. I set DispatcherServlet's setThreadContextInheritable() to true, so that my ServletRequestAttributes instance can be passed to child thread for its task. Debugging shows the ServletRequestAttributes instance is set inactive status and cached in RequestContextHolder when child thread in async call and that stops child thread to get some values from the attributes object. Debugging shows at line 989 of FrameworkServlet.java, it calls requestCompleted() right after parent thread process the request. Here is my Application.java snippets:

 @SpringBootApplication(exclude = DispatcherServletAutoConfiguration.class)
 @EnableAsync 
 public class Application extends AsyncConfigurerSupport {
  @Override
  public Executor getAsyncExecutor() {
    SimpleAsyncTaskExecutor executor = new 
    SimpleAsyncTaskExecutor(appProperties.threadNamePrefix);
    return executor;
  }
  @Bean
  public ServletRegistrationBean registerAirportDispatchServlet() {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
    dispatcherServlet.setApplicationContext(applicationContext);
    dispatcherServlet.setThreadContextInheritable(true);
    ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/*");
    servletRegistrationBean.setName("MyDispacherServlet");
    return servletRegistrationBean;
  }
}

My REST Controller async snippets:

@RestController
public class AsyncController {
  @RequestMapping(path = "/async", method = RequestMethod.POST)
  @Async
  public DeferredResult<ResponseEntity<String>> doAsync(
    DeferredResult<ResponseEntity<String>> result = new DeferredResult<>();
    ServletRequestAttributes attributes =  
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    result.setResult(doLongTask());
    return result;
  }
}

You can easily verify the attributes object returned from RequestContextHolder
is in inactive. This will cost issue down the path especially when child thread
enables JPA auditing and updates DB data where child thread need to access current
security token stored in ServletRequestAttributes instance from RequestContextHolder.
i got error message: "Cannot ask for request attribute - request is not active anymore!"

I think for async REST calls, if inheritable flag is set to true, FrameworkServlet shouldn't
mark the request attributes to inactive especially child thread hasn't finish its job
yet. Should leave the attributes instance as it is in RequestContextHolder for child thread.


Affects: 4.3.6

Reference URL: https://stackoverflow.com/questions/44121654/inherited-servletrquestattributes-is-marked-completed-before-child-thread-finish

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
1 participant
You can’t perform that action at this time.