He-Pin opened a new issue, #3695:
URL: https://github.com/apache/pekko/issues/3695

   ## Summary
   
   When a CI job hangs, nothing captures a thread dump and most jobs have no 
`timeout-minutes`, so the run eventually dies on the runner's own global limit 
and the log contains no clue about what was blocked. Given that the test suite 
has several code paths that can block indefinitely, this turns an investigable 
hang into an unexplained red build.
   
   ## Current state
   
   There are 40 workflow files under `.github/workflows/`. `timeout-minutes` 
appears exactly once in all of them:
   
   ```
   .github/workflows/nightly-multi-jvm-tests.yml:32:    timeout-minutes: 240
   ```
   
   `build-test-prValidation.yml` — the workflow that runs on every PR — sets 
none.
   
   No workflow captures diagnostics on a hang. Searching for the usual 
mechanisms returns nothing:
   
   ```
   rg -in 'jstack|jcmd|thread.?dump|blame-hang' .github/workflows/
   (no matches)
   ```
   
   ## Why hangs are plausible here
   
   The testkit contains at least three paths that can block without a deadline:
   
   **`TestKit.within` does not interrupt its block.** 
`testkit/src/main/scala/org/apache/pekko/testkit/TestKit.scala:415,426-436`:
   
   ```scala
       val _max = max.dilated
       ...
       val ret =
         try f
         finally end = prev_end
   
       val diff = now - start
       assert(min <= diff, s"block took ${format(min.unit, diff)}, should at 
least have been $min")
       if (!lastWasNoMsg) {
         assert(diff <= max_diff, s"block took ${format(_max.unit, diff)}, 
exceeding ${format(_max.unit, max_diff)}")
       }
   ```
   
   The budget is only checked *after* `f` returns. A block that never returns 
hangs the test forever; `within` provides no watchdog.
   
   **`Player.enter` awaits with `Duration.Inf`.** 
`multi-node-testkit/src/main/scala/org/apache/pekko/remote/testconductor/Player.scala:124`:
   
   ```scala
           Await.result(client ? ToServer(EnterBarrier(b, 
Option(barrierTimeout))), Duration.Inf)
   ```
   
   **`Controller` blocks on a Netty future inside a message handler.** 
`multi-node-testkit/src/main/scala/org/apache/pekko/remote/testconductor/Conductor.scala:531-532`:
   
   ```scala
       case GetSockAddr =>
         sender() ! connection.channelFuture.sync().channel().localAddress()
   ```
   
   This one is filed separately, but it is an example of the general shape: a 
blocked actor thread that also hosts the barrier coordinator.
   
   ## Proposal
   
   Two changes, both confined to `.github/`:
   
   1. **Capture thread dumps when a test step exceeds its budget.** Run the sbt 
invocation under a watchdog that, on expiry, executes `jcmd <pid> Thread.print` 
(or `jstack -l <pid>`) for every JVM in the process tree and uploads the output 
as an artifact *before* killing the step. sbt forks test JVMs, so the watchdog 
needs to find the children rather than only the sbt launcher.
   
   2. **Add `timeout-minutes` to the PR validation jobs**, set well below the 
runner default and above the observed p99 for each job, so a hang fails fast 
with the dump attached instead of consuming the full runner limit.
   
   A dump on hang is worth more than the timeout itself: the timeout only tells 
you the build is red, while the dump usually names the blocked thread and the 
lock or `Await` it is stuck in — which for a distributed-systems test suite is 
very often the actual bug rather than a CI annoyance.
   
   ## Scope
   
   CI configuration only. No production or test-source change.
   


-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to