You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pekko.apache.org by he...@apache.org on 2026/07/05 13:38:54 UTC
(pekko) branch main updated: Fix timer current message for supervision #3265 (#3294)
This is an automated email from the ASF dual-hosted git repository.
He-Pin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko.git
The following commit(s) were added to refs/heads/main by this push:
new bafe8a944d Fix timer current message for supervision #3265 (#3294)
bafe8a944d is described below
commit bafe8a944d5bf1793159cc96799f7b8f4413a92c
Author: He-Pin(kerr) <he...@gmail.com>
AuthorDate: Sun Jul 5 21:38:48 2026 +0800
Fix timer current message for supervision #3265 (#3294)
Motivation:
Timer-triggered failures in non-stash actors exposed the internal TimerMsg wrapper to preRestart instead of the user message delivered to receive.
Modification:
Rewrite ActorCell.currentMessage to the unwrapped timer message for all Timers actors and add a regression test for non-stash timer supervision.
Result:
preRestart observes the same unwrapped user message that receive processed, while existing timer and stash behavior remains covered.
Tests:
- sbt "actor-tests / Test / testOnly org.apache.pekko.actor.TimersAndSupervisionSpec org.apache.pekko.actor.TimersAndStashSpec org.apache.pekko.actor.TimerSpec" - passed
- sbt "actor-tests / Test / testOnly org.apache.pekko.actor.FsmTimerSpec" - passed
- sbt "actor-tests / Test / testOnly org.apache.pekko.actor.TimersAndSupervisionSpec org.apache.pekko.actor.TimersAndStashSpec" - passed
- scalafmt --mode diff-ref=origin/main - passed with JDK Unsafe deprecation warnings
- scalafmt --list --mode diff-ref=origin/main - passed with JDK Unsafe deprecation warnings
- git diff --check - passed
- qodercli final diff review - No must-fix findings
References:
Fixes #3265
---
.../scala/org/apache/pekko/actor/TimerSpec.scala | 40 ++++++++++++++++++++++
.../main/scala/org/apache/pekko/actor/Timers.scala | 11 ++----
2 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/actor-tests/src/test/scala/org/apache/pekko/actor/TimerSpec.scala b/actor-tests/src/test/scala/org/apache/pekko/actor/TimerSpec.scala
index 85e67b77ec..ec02dd80f2 100644
--- a/actor-tests/src/test/scala/org/apache/pekko/actor/TimerSpec.scala
+++ b/actor-tests/src/test/scala/org/apache/pekko/actor/TimerSpec.scala
@@ -321,6 +321,46 @@ object TimersAndStashSpec {
case object StopStashing
}
+
+object TimersAndSupervisionSpec {
+
+ case object StartTimer
+ case object Scheduled
+
+ class FailingTimerActor(probe: ActorRef) extends Actor with Timers {
+ override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
+ probe ! message
+ super.preRestart(reason, message)
+ }
+
+ def receive: Receive = {
+ case StartTimer => timers.startSingleTimer("key", Scheduled, 10.millis)
+ case Scheduled => throw new TimerSpec.Exc
+ }
+ }
+
+}
+
+class TimersAndSupervisionSpec extends PekkoSpec {
+ import TimersAndSupervisionSpec._
+
+ "Timers combined with supervision" should {
+
+ "pass the unwrapped timer message to preRestart for non-stash actors" taggedAs TimingTest in {
+ val probe = TestProbe()
+ val actor = system.actorOf(Props(new FailingTimerActor(probe.ref)))
+
+ actor ! StartTimer
+
+ probe.expectMsg(Some(Scheduled))
+ watch(actor)
+ system.stop(actor)
+ expectTerminated(actor)
+ }
+ }
+
+}
+
class TimersAndStashSpec extends PekkoSpec {
import TimersAndStashSpec._
diff --git a/actor/src/main/scala/org/apache/pekko/actor/Timers.scala b/actor/src/main/scala/org/apache/pekko/actor/Timers.scala
index 9c57c6100b..c75574be4d 100644
--- a/actor/src/main/scala/org/apache/pekko/actor/Timers.scala
+++ b/actor/src/main/scala/org/apache/pekko/actor/Timers.scala
@@ -55,14 +55,9 @@ trait Timers extends Actor {
case OptionVal.Some(m: AutoReceivedMessage) =>
context.asInstanceOf[ActorCell].autoReceiveMessage(Envelope(m, self, context.system))
case OptionVal.Some(m) =>
- if (this.isInstanceOf[StashSupport]) {
- // This is important for stash interaction, as stash reads the message directly from
- // currentMessage (StashSupport) #24557. We match StashSupport rather than Stash so that
- // actors mixing in UnboundedStash or UnrestrictedStash directly - which are siblings of
- // Stash, not subtypes - also rewrite the unwrapped timer message; otherwise stash()
- // would re-stash the TimerMsg wrapper and the message would be lost on unstash (#3258).
- actorCell.currentMessage = actorCell.currentMessage.copy(message = m)
- }
+ // Keep the cell-wide current message consistent with the message delivered to receive.
+ // Stash and failure handling both read currentMessage directly.
+ actorCell.currentMessage = actorCell.currentMessage.copy(message = m)
super.aroundReceive(receive, m)
case _ => // discard
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pekko.apache.org
For additional commands, e-mail: commits-help@pekko.apache.org