TL;DR

The threads were waiting on external I/O performed inside transaction boundaries. A synchronous Spring event listener published to ActiveMQ before the transaction committed — and the same pattern repeated around Firebase, S3, and SMS.

Recap

The infrastructure investigation in Part 1 narrowed the problem to a precise shape: threads were holding Hikari connections without doing database work. The database itself was healthy. The application was the problem.

There was one more correlation that turned out to be the anchor for everything that followed. During the same 15-minute window when Hikari was failing, the ActiveMQ broker had been unavailable. The broker's connection failures started just before the Hikari errors and recovered at the same moment Hikari recovered.