codeconsole opened a new issue, #16219:
URL: https://github.com/apache/grails-core/issues/16219

   `functionaltests.async.AsyncPromiseSpec` fails intermittently, and not 
always on the same feature, when the HTTP client gives up waiting for a 
response:
   
   ```
   java.net.http.HttpTimeoutException: request timed out
       at 
java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:953)
       at 
org.apache.grails.testing.http.client.HttpClientSupport$Trait$Helper.send(HttpClientSupport.groovy:1133)
       at 
org.apache.grails.testing.http.client.HttpClientSupport$Trait$Helper.http(HttpClientSupport.groovy:203)
       at 
functionaltests.async.AsyncPromiseSpec.<feature>(AsyncPromiseSpec.groovy:<line>)
   ```
   
   The client timeout is 120 seconds (`grails.http.client.timeout`, set in 
`gradle/functional-test-config.gradle`).
   
   ## Occurrences
   
   | Date (UTC) | Branch | Job | Feature that timed out |
   |---|---|---|---|
   | 2026-07-29 20:32 | `feat/8.0.x-legacy-command-compat` | [Hibernate7 
Functional Tests (Java 21, 
indy=true)](https://github.com/apache/grails-core/actions/runs/30488829586/job/90701275362)
 | conditional async uses sync mode when requested |
   | 2026-07-29 21:01 | **`8.0.x`** | [Functional Tests (Java 21, 
indy=false)](https://github.com/apache/grails-core/actions/runs/30490747146/job/90707733744)
 | multi-stage process reports all stages |
   | 2026-08-22 17:23 | `fix/embedded-mongo-replica-set` | [Build Grails with 
Groovy snapshot (shard 
2)](https://github.com/apache/grails-core/actions/runs/32587420540/job/97066257811)
 | conditional async uses sync mode when requested |
   | 2026-08-24 23:53 | `ci/…` on #16214 | [Build Grails with Groovy snapshot 
(shard 
0)](https://github.com/apache/grails-core/actions/runs/32791117146/job/97633380610)
 | async service processes string input |
   
   Found by scanning the failed job logs of every `CI` and `CI - Groovy Joint 
Validation Build` run between 2026-07-20 and 2026-08-24 - 308 logs, none 
unavailable - for that spec together with that exception. These four are all of 
them in that period.
   
   Three different features, two different applications 
(`grails-test-examples-app1` and `grails-test-examples-hibernate7-app1`), both 
indy settings, and one of them on `8.0.x` itself. Everything else in the same 
specification passes in the same run: on 2026-08-24, 695 tests completed, 1 
failed.
   
   ## Why a timeout here is odd
   
   The 2026-08-24 failure was on `/asyncTest/useAsyncService`, and that action 
cannot take 120 seconds:
   
   ```groovy
   def useAsyncService() {
       def input = params.input ?: 'hello'
       def future = asyncProcessingService.processAsync(input)
       def result = future.get(5, TimeUnit.SECONDS)     // bounded
       render([input: input, result: result] as JSON)
   }
   ```
   
   The worst it can do is throw after five seconds and return a 500. A client 
that waits 120 seconds and receives nothing suggests the request was never 
served, rather than that this action was slow.
   
   ## Possibly relevant, not established
   
   The feature declared immediately before it in the same controller 
deliberately abandons a thread on every data-driven case:
   
   ```groovy
   def workThread = Thread.start {
       sleep(delay)
       completed.set(true)
   }
   workThread.join(timeout)          // 10 ms, while the work sleeps 100 ms
   if (!completed.get()) {
       workThread.interrupt()
       message = "Task exceeded timeout of ${timeout} ms"
   }
   ```
   
   A raw thread per request, interrupted mid-sleep, is the kind of thing that 
leaves debris under load - but nothing here shows that it is what starves the 
later request, and the 2026-07-29 failures were on other features.
   
   ## What has been ruled out
   
   The promise decorator change in #16192 
(`AsyncWebRequestPromiseDecoratorLookupStrategy`, which stops decorating a 
request the container will not start a new asynchronous cycle on). Two of the 
four occurrences are from 2026-07-29, three and a half weeks before that change 
was written, and one of those is on `8.0.x`.
   
   ## Reproducing
   
   Not reproduced locally. `:grails-test-examples-app1:integrationTest --tests 
"*AsyncPromiseSpec*"` was run four times in a row - 84 tests, no failures - and 
the hibernate7 application's copy three times before that.
   
   ## Suggested next step
   
   The failure says only that the client gave up. What would settle it is the 
server's side of the same moment: whether the request arrived at all. An access 
log on these applications during functional tests, or a thread dump taken when 
a request exceeds the client timeout, would distinguish "never served" from 
"served slowly" - which is the fork this depends on.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to