Skip to content

Commit

Permalink
Akka.Router: automatically unpack IScheduledTellMsg when being hand…
Browse files Browse the repository at this point in the history
…led through a router (#7249)

* added initial reproduction for #7247

* reproduced #7247

* have fix; working on repro

* close #7247 - ensured routers drop IScheduledTellMsg to non-ActorCell'd routees

* added timeout back

* removed .NET 6-only call

---------

Co-authored-by: Gregorius Soedharmo <arkatufus@yahoo.com>
  • Loading branch information
Aaronontheweb and Arkatufus authored Jun 13, 2024
1 parent 487218c commit 6bcab70
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
67 changes: 67 additions & 0 deletions src/core/Akka.Tests/Actor/Scheduler/BugFix7247Spec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// -----------------------------------------------------------------------
// <copyright file="7247BugFixSpec.cs" company="Akka.NET Project">
// Copyright (C) 2009-2024 Lightbend Inc. <http://www.lightbend.com>
// Copyright (C) 2013-2024 .NET Foundation <https://github.com/akkadotnet/akka.net>
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Routing;
using Akka.TestKit;
using Akka.Util.Internal;
using FluentAssertions;
using Xunit;

namespace Akka.Tests.Actor.Scheduler;

public class BugFix7247Spec : AkkaSpec {
public sealed class NoCellActorRef : MinimalActorRef
{
public NoCellActorRef(ActorPath path, TaskCompletionSource<object> firstMessage)
{
Path = path;
FirstMessage = firstMessage;
}

protected override void TellInternal(object message, IActorRef sender)
{
FirstMessage.TrySetResult(message);
}

public TaskCompletionSource<object> FirstMessage { get; }

public override ActorPath Path { get; }
public override IActorRefProvider Provider => throw new NotImplementedException();
}

[Fact(DisplayName = "Should not send ScheduledTellMsg envelopes to IActorRefs with no cell")]
public async Task ShouldNotSendScheduledTellMsgToNoCellActorRefs()
{
// arrange
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
var noCellRef = Sys.As<ExtendedActorSystem>().Provider.CreateFutureRef(tcs);
var router = Sys.ActorOf(Props.Empty.WithRouter(new BroadcastGroup()));
var routee = Routee.FromActorRef(noCellRef);
router.Tell(new AddRoutee(routee));

await AwaitAssertAsync(async () =>
{
var allRoutees = await router.Ask<Routees>(GetRoutees.Instance);
allRoutees.Members.Count().ShouldBeGreaterThan(0);
});

// act
var msg = "hit";
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(0.5));
Sys.Scheduler.ScheduleTellOnce(TimeSpan.FromMilliseconds(1), router, msg, ActorRefs.NoSender);
await tcs.Task.WithCancellation(cts.Token); // will time out if we don't get our msg
var respMsg = await tcs.Task;

// assert
Assert.Equal(msg, respMsg);
}
}
10 changes: 9 additions & 1 deletion src/core/Akka/Routing/RoutedActorCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Linq;
using Akka.Actor;
using Akka.Actor.Internal;
using Akka.Actor.Scheduler;
using Akka.Dispatch;
using Akka.Util;
using Akka.Util.Internal;
Expand Down Expand Up @@ -193,7 +194,14 @@ public override void SendMessage(Envelope envelope)
if (RouterConfig.IsManagementMessage(envelope.Message))
base.SendMessage(envelope);
else
Router.Route(envelope.Message, envelope.Sender);
{
// Bugfix: https://github.com/akkadotnet/akka.net/issues/7247
if(envelope.Message is IScheduledTellMsg scheduledTellMsg)
Router.Route(scheduledTellMsg.Message, envelope.Sender);
else
Router.Route(envelope.Message, envelope.Sender);
}

}

/// <summary>
Expand Down

0 comments on commit 6bcab70

Please sign in to comment.