question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

0.25.2 generates a 409/Conflict responses with Async results

See original GitHub issue

Hi team,

I discovered a regression after upgrading from Spring Boot 2.1.6 to 2.1.7 and especially with the upgrade from hateoas 0.25.1 to 0.25.2.

We have a controller defined like this (note the async result)

@RestController
@RequestMapping("/api/foo")
@ExposesResourceFor(FooStuffs.class)
public class FooStuffsController {

  @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
  public Future<FooStuffs> getFooFromToDate(@RequestParam("fromDate") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)  LocalDate fromDate,
                                               @RequestParam(value = "toDate", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)  LocalDate optionalToDate) {
....
}

Which was working before:

2019-10-18 21:51:54.386 DEBUG 7242 --- [  XNIO-1 task-3] o.s.web.servlet.DispatcherServlet        : "ASYNC" dispatch for GET "/api/foo?fromDate=2019-10-01&toDate=2019-10-18", parameters={masked}
2019-10-18 21:51:54.390 DEBUG 7242 --- [  XNIO-1 task-3] s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result [FooStuffs{fromDate=2019-10-01, toDate=2019-10-08, foo=[]}]

And now it fails with a Conflict / 409 http error:

2019-10-18 21:55:30.858 DEBUG 7552 --- [  XNIO-1 task-3] o.s.web.servlet.DispatcherServlet        : "ASYNC" dispatch for GET "/api/foo?fromDate=2019-10-01&toDate=2019-10-18", parameters={masked}
2019-10-18 21:55:30.861 DEBUG 7552 --- [  XNIO-1 task-3] s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result [java.lang.IllegalStateException: Cannot ask for request attribute - request is not active anymore!]

Digging a bit (thanks @bclozel @snicoll) I found that it is a side effect of PR #749

The problem is about the cache which is using RequestAttributes.SCOPE_REQUEST

https://github.com/spring-projects/spring-hateoas/commit/77392de587afc2b02b300a5129b9146af952adf9#diff-98e861a165d7d9d2bc81e5ecd48cdb96R114-R125

but it’s not active because of the async and thus we get the IllegalStateException

https://github.com/spring-projects/spring-framework/blob/5.1.x/spring-web/src/main/java/org/springframework/web/context/request/ServletRequestAttributes.java#L149

I am not sure if hateoas is supposed to support Async results (I didn’t find any doc to deny or validate it). Let me know if I can help more @odrotbohm @gregturn

NOTE: I didn’t try with 1.x but as far as I can see the code of UriComponentsBuilderFactory didn’t change.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:14 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
aheritiercommented, May 6, 2020

@gregturn I found the issue \o/ and I am happy to share that it’s not bug in hateoas !!!

I found that a previous developer implemented a workaround to allow hateoas to work with Async when it was not supported. For this he wrote a specific config for the Servlet Dispatcher … While it was explained in the class comment the name of the Config amongst all others never caught my eye. Removing it is solving my issue. The bug was in our app because of the conflict between the workaround and the fix done in 0.25.2 … I am now safe to upgrade

/**
 * Fixes issue in Spring HATEOAS where RequestContextHolder is not available when using asynchronous service requests.
 */
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(WebMvcProperties.class)
public class DispatcherServletConfig {

  private final WebMvcProperties webMvcProperties;

  public DispatcherServletConfig(WebMvcProperties webMvcProperties) {
    this.webMvcProperties = webMvcProperties;
  }

  @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  public DispatcherServlet dispatcherServlet() {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();

    dispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest());
    dispatcherServlet.setDispatchTraceRequest(this.webMvcProperties.isDispatchTraceRequest());
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(this.webMvcProperties.isThrowExceptionIfNoHandlerFound());

    return dispatcherServlet;
  }

  @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
  public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
    ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(dispatcherServlet, this.webMvcProperties.getServlet().getServletMapping());

    registration.setName(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
    registration.setLoadOnStartup(this.webMvcProperties.getServlet().getLoadOnStartup());

    dispatcherServlet.setThreadContextInheritable(true); // Enable request attributes in spawned threads

    return registration;
  }

  @Bean
  @ConditionalOnMissingBean(DispatcherServletPath.class)
  @ConditionalOnSingleCandidate(DispatcherServlet.class)
  public DispatcherServletPath dispatcherServletPath() {
    return () -> webMvcProperties.getServlet().getPath();
  }
}
1reaction
gregturncommented, Apr 14, 2020

Seeing as we have no test cases surrounding async Spring MVC behavior, I’d like to work on one so we have somewhere to go. First and foremost, I want to see if this issue exists on the master branch, and then work from there.

If it does, we patch it and then assess backporting the fix to earlier versions.

Read more comments on GitHub >

github_iconTop Results From Across the Web

409 Conflict - HTTP - MDN Web Docs
The HTTP 409 Conflict response status code indicates a request conflict with the current state of the target resource.
Read more >
How To Fix the “409 Conflict” Error (5 Methods) - Kinsta
The "409 conflict" error can be frustrating, but it is actually easy to fix. Learn how to fix the error using 5 different...
Read more >
Return an object along with a 409 Conflict error in a Web API ...
I have a C# Entity Framework Web API 2 controller. Currently when an attempt is made via the POST method to create an...
Read more >
"409 Conflict" causes Runner to not run any jobs, and give up ...
409 Conflict errors are normal and expected in cases where you have multiple runners configured and trying to pick up the same job....
Read more >
Snapshot Debugger (409) Conflict - Visual Studio Feedback
WebException: The remote server returned an error: (409) Conflict. at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) at System.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found