Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Akka.Router: sending a message to a remote actor via IScheduledTellMsg results in serialization error #7247

Closed
Aaronontheweb opened this issue Jun 11, 2024 · 1 comment

Comments

@Aaronontheweb
Copy link
Member

Version Information
Version of Akka.NET? v1.5.13 and higher
Which Akka.NET Modules? Akka.Remote

Describe the bug

This bug was introduced in Akka.NET v1.5.13 via #6461

Repro from our Discord - imagine you have the following code:

 public class SchedulerActor : ReceiveActor
    {
        private readonly IActorRef _receiverActor;
        private readonly ILoggingAdapter _log = Context.GetLogger();

        public SchedulerActor(IActorRef receiverActor)
        {
            _receiverActor = receiverActor;

            // Schedule the first message
            ScheduleMessage();
        }

        private void ScheduleMessage()
        {
            Context.System.Scheduler.ScheduleTellRepeatedly(
                initialDelay: TimeSpan.FromSeconds(1),
                interval: TimeSpan.FromSeconds(5),
                receiver:  _receiverActor,
                message: new Tick(),
                sender: Self);
        }

        // Tick message class
        public class Tick
        {
        }
    }

Imagine if the _receiverActor is a RemoteActorRef - this will cause the Tick message to be wrapped inside a ScheduledTellMsg

internal sealed class ScheduledTellMsg : IScheduledTellMsg
{
public ScheduledTellMsg(object message)
{
Message = message;
}
public object Message { get; }
}

Now this might not normally be a problem for many serializers - Newtonsoft.Json can probably handle this just fine. But it completely disrupts custom serialization and prevents it from working correctly.

We added ScheduledTellMsg in order to make it easier for libraries like Phobos in order to stop us from tracing scheduled messages, since that's almost always useless noise.

Expected behavior

ScheduledTellMsg is supposed to be automatically unpacked by the ActorCell - therefore it should never be something that pops into user-space.

Actual behavior

However, RemoteActorRefs do not have an ActorCell! Therefore the message never gets unpacked and will, instead, be serialized and transmitted over the network. This is a bug - we probably need to just unpack the underlying message and send that sans the ScheduledTellMsg envelope.

@Aaronontheweb Aaronontheweb added this to the 1.5.25 milestone Jun 11, 2024
Aaronontheweb added a commit to Aaronontheweb/akka.net that referenced this issue Jun 12, 2024
Aaronontheweb added a commit to Aaronontheweb/akka.net that referenced this issue Jun 12, 2024
Aaronontheweb added a commit to Aaronontheweb/akka.net that referenced this issue Jun 12, 2024
@Aaronontheweb Aaronontheweb changed the title Akka.Remote: sending a message to a remote actor via IScheduledTellMsg results in serialization error Akka.Router: sending a message to a remote actor via IScheduledTellMsg results in serialization error Jun 12, 2024
@Aaronontheweb
Copy link
Member Author

As it turns out, this was not an issue with Akka.Remote or with the scheduler at all - but rather it was really an issue with routers in Akka.NET. The key actor in the reproduction was a router.

We've had measures in-place to prevent IScheduledTellM,sg from being serialized from the beginning:

public ScheduledTell(ICanTell receiver, object message, IActorRef sender)
{
_receiver = receiver;
_message = receiver is not ActorRefWithCell
? message
: message is INotInfluenceReceiveTimeout
? new ScheduledTellMsgNoInfluenceReceiveTimeout(message)
: new ScheduledTellMsg(message);
_sender = sender;
}

That code would detect a RemoteActorRef and not include the ScheduledTellMsg envelope in order to prevent serialization issues.

However, as it turns out - we do send ScheduledTellMsgs to routers (because they have a RoutedActorCell) and those messages can still be forwarded to RemoteActorRefs with the IScheduledTellMsg wrapper intact:

public override void SendMessage(Envelope envelope)
{
if (RouterConfig.IsManagementMessage(envelope.Message))
base.SendMessage(envelope);
else
Router.Route(envelope.Message, envelope.Sender);
}

That's what we need to fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant