Pekko Actor Heartbeat Timeouts During Default Dispatcher Saturation
0 reputation · 01 Oct 2023, 01:25 UTC
0 reputation · 01 Oct 2023, 01:25 UTC
In a standard JVM-based Pekko deployment, the goal is to determine whether actor heartbeat and timeout mechanisms can misfire when the default dispatcher's ForkJoinPool is saturated by concurrent blocking I/O calls. The default dispatcher shares a fixed pool across non-blocking actor logic, and synchronous operations such as JDBC calls are documented as unsuitable for this pool because they can cause thread starvation.
The uncertainty is whether dispatcher exhaustion delays heartbeat messages or scheduled timeouts independently of actual application failures, particularly under extreme load where JVM garbage collection pauses may compound scheduling delays. The bounded-blocking dispatcher is documented for isolating blocking work, but its interaction with actor supervision timeouts remains unresolved.
35775 reputation · 01 Oct 2023, 08:37 UTC
Yes, default dispatcher saturation directly delays Pekko actor heartbeat delivery and the triggering of scheduled timeouts. Because heartbeats and timeout ticks are processed as messages on the actor's assigned dispatcher, they are subject to the same scheduling queue as application logic. When the ForkJoinPool reaches its parallelism capacity due to blocking I/O, these control messages remain queued, leading to delayed execution regardless of the actor's actual health.
Under default configurations, heartbeat failures caused by dispatcher starvation are indistinguishable from genuine actor liveness failures. In both scenarios, the supervisor or monitoring actor fails to receive a heartbeat within the expected window. The system cannot natively differentiate between a thread that is blocked on a JDBC call and a process that has crashed or hung, as both result in the same observable outcome: a missed heartbeat.
To prevent false-positive supervision triggers, you must isolate blocking operations from the control plane. Follow these steps:
bounded-blocking-dispatcher. This ensures the default dispatcher remains available to process heartbeats and timeouts.To verify if dispatcher saturation is the root cause, use the following approach:
ForkJoinPool active thread count and queue size. If the active count equals the parallelism limit while heartbeats are failing, starvation is occurring.Missing Diagnostic Detail: Are you currently utilizing receiveTimeout for heartbeats, or are you using a separate scheduler to send periodic heartbeat messages? The recommendation for timeout measurement differs slightly depending on whether the timer is internal to the actor or external.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.