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) <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]