chris
chris

Reputation: 3

akka.net first published message ends up in the dead letter queue, handshake problem

I have an issue with an akka.net message send/Tell that ends up in the dead letter queue. I developed a cluster based application using Akka.Cluster.Tools.PublishSubscribe with two ActorSystems each running in a 'console.application' on the same machine.

I start up one actor system with some actors. Then I start up my 2nd. application and immediatelly after I initialized the Actor system I publish the first Message Mediator.Tell(new Publish(Topics.Backend.SomeName, new MyInitialMessage())) to a Topic where the receiving actor is hosted in the 1st. application. This message ends up in the dead letter queue always.

Ok now, instead of sending the message immediatelly I put in a delay of e.g 5sec. Then the message could be delivered properly. This seems to me as a handshake problem.

Question: How do I find out when the 2nd. actor system is ready to receive any messages??

My current workaround is: I send scheduler based for each second a MyInitialMessage and wait for the first response message from my 2nd. application. Then I know my 2nd. app is now ready, handshake done. But this seems to me just as a workaround. What would be a proper solution to this issue?

chris

Upvotes: 0

Views: 395

Answers (1)

Bartosz Sypytkowski
Bartosz Sypytkowski

Reputation: 7542

Akka.Cluster.Tools.PublishSubscribe works over cluster. You need to await for cluster to become initialized before you'll be able to publish any messages. All of cluster operations are encapsulated in Cluster class that can be created from any actor system using Cluster.Get(actorSystem). In order to wait for cluster to initialize:

  1. You can join to cluster programmatically by using await cluster.JoinAsync(address, cancellationToken) - you can use it to initialize both seed nodes (just make actor system join to itself) and new nodes. This will require to leave seed-nodes in your HOCON configuration empty.
  2. If you're initializing cluster from configuration (using HOCON config file), you can register a callback function using cluster.RegisterOnMemberUp(callback) to postpone the rest of processing until local actor system successfully joined the cluster.

The fastest (in terms of performance and resource usage) way is to subscribe to cluster membership events from within a particular actor. In fact this is how other solutions described above are actually implemented under the hood.

class MyActor : ReceiveActor 
{
    readonly Cluster cluster = Akka.Cluster.Cluster.Get(Context.System);
    public MyActor() 
    {
        Receive<ClusterEvent.MemberUp>(up => 
        {
            if (up.Member.Address == cluster.SelfAddress) 
            {
                Become(Ready);
            }
        });
    }

    protected override void PreStart() 
    {
        cluster.Subscribe(Self, new[]{ typeof(ClusterEvent.IMemberEvent) });
    }
    
    protected override void PostStop() 
    {
        // rember to unsubscribe once actor is stopping
        cluster.Subscribe(Self);
    }

    void Ready() 
    {
        // other receiver handlers
    }
}

Upvotes: 0

Related Questions