Exemplo n.º 1
0
        public async void CanSendJsonAndReceiveToExistingRemote()
        {
            var remoteActor = new PID(_remoteManager.DefaultNode.Address, "EchoActorInstance");
            var ct          = new CancellationTokenSource(3000);
            var tcs         = new TaskCompletionSource <bool>();

            ct.Token.Register(() =>
            {
                tcs.TrySetCanceled();
            });

            var localActor = Actor.Spawn(Actor.FromFunc(ctx =>
            {
                if (ctx.Message is Pong)
                {
                    tcs.SetResult(true);
                    ctx.Self.Stop();
                }

                return(Actor.Done);
            }));

            var json     = new JsonMessage("remote_test_messages.Ping", "{ \"message\":\"Hello\"}");
            var envelope = new Proto.MessageEnvelope(json, localActor, Proto.MessageHeader.EmptyHeader);

            Remote.SendMessage(remoteActor, envelope, 1);
            await tcs.Task;
        }
        public async Task MessagesGoToDeadLetterAfterConnectionFail()
        {
            var logger = Log.CreateLogger("ConnectionFail");

            var remoteActor  = new PID("127.0.0.1:12000", "EchoActorInstance");
            var ct           = new CancellationTokenSource(30000);
            var receivedPong = new TaskCompletionSource <bool>();
            var receivedDeadLetterEventTcs = new TaskCompletionSource <bool>();

            ct.Token.Register(
                () =>
            {
                receivedPong.TrySetCanceled();
                receivedDeadLetterEventTcs.TrySetCanceled();
            }
                );

            EventStream.Instance.Subscribe <DeadLetterEvent>(
                deadLetterEvt =>
            {
                if (deadLetterEvt.Message is JsonMessage)
                {
                    receivedDeadLetterEventTcs.TrySetResult(true);
                }
            }
                );

            var localActor = RootContext.Empty.Spawn(
                Props.FromFunc(
                    ctx =>
            {
                if (ctx.Message is Pong)
                {
                    receivedPong.SetResult(true);
                    ctx.Stop(ctx.Self);
                }

                return(Actor.Done);
            }
                    )
                );

            var json     = new JsonMessage("remote_test_messages.Ping", "{ \"message\":\"Hello\"}");
            var envelope = new Proto.MessageEnvelope(json, localActor, Proto.MessageHeader.Empty);

            logger.LogDebug("sending message while offline");
            Remote.SendMessage(remoteActor, envelope, 1);

            logger.LogDebug("waiting for connection to fail after retries and fire a terminated event");
            await receivedDeadLetterEventTcs.Task;

            //Should reconnect if we send a new message
            await Task.Delay(2000, ct.Token);

            logger.LogDebug("Sending new message now that remote is up");
            Remote.SendMessage(remoteActor, envelope, 1);

            logger.LogDebug("Waiting for response to message");
            await receivedPong.Task;
        }
Exemplo n.º 3
0
        public override async Task Receive(IAsyncStreamReader <MessageBatch> requestStream,
                                           IServerStreamWriter <Unit> responseStream, ServerCallContext context)
        {
            var targets = new PID[100];
            await requestStream.ForEachAsync(batch =>
            {
                if (_suspended)
                {
                    return(Actor.Done);
                }

                //only grow pid lookup if needed
                if (batch.TargetNames.Count > targets.Length)
                {
                    targets = new PID[batch.TargetNames.Count];
                }

                for (int i = 0; i < batch.TargetNames.Count; i++)
                {
                    targets[i] = new PID(ProcessRegistry.Instance.Address, batch.TargetNames[i]);
                }
                var typeNames = batch.TypeNames.ToArray();
                foreach (var envelope in batch.Envelopes)
                {
                    var target   = targets[envelope.Target];
                    var typeName = typeNames[envelope.TypeId];
                    var message  = Serialization.Deserialize(typeName, envelope.MessageData, envelope.SerializerId);

                    if (message is Terminated msg)
                    {
                        var rt = new RemoteTerminate(target, msg.Who);
                        EndpointManager.RemoteTerminate(rt);
                    }
                    else if (message is SystemMessage sys)
                    {
                        target.SendSystemMessage(sys);
                    }
                    else
                    {
                        Proto.MessageHeader header = null;
                        if (envelope.MessageHeader != null)
                        {
                            header = new Proto.MessageHeader();
                            foreach (var(k, v) in envelope.MessageHeader.HeaderData)
                            {
                                header.Add(k, v);
                            }
                        }
                        var localEnvelope = new Proto.MessageEnvelope(message, envelope.Sender, header);
                        target.Tell(localEnvelope);
                    }
                }

                return(Actor.Done);
            });
        }
Exemplo n.º 4
0
        private void ReceiveMessages(MessageEnvelope envelope, object message, PID target)
        {
            Proto.MessageHeader?header = null;

            if (envelope.MessageHeader is not null)
            {
                header = new Proto.MessageHeader(envelope.MessageHeader.HeaderData);
            }

            // Logger.LogDebug("[EndpointReader] Forwarding remote user message {@Message}", message);
            var localEnvelope = new Proto.MessageEnvelope(message, envelope.Sender, header);

            _system.Root.Send(target, localEnvelope);
        }
        public async Task CanRecoverFromConnectionFailureAsync()
        {
            var logger = Log.CreateLogger("ConnectionFail");

            var remoteActor            = new PID("127.0.0.1:12000", "EchoActorInstance");
            var ct                     = new CancellationTokenSource(30000);
            var tcs                    = new TaskCompletionSource <bool>();
            var receivedTerminationTcs = new TaskCompletionSource <bool>();

            ct.Token.Register(
                () =>
            {
                tcs.TrySetCanceled();
                receivedTerminationTcs.TrySetCanceled();
            }
                );

            EventStream.Instance.Subscribe <EndpointTerminatedEvent>(termEvent => receivedTerminationTcs.TrySetResult(true));

            var localActor = RootContext.Empty.Spawn(
                Props.FromFunc(
                    ctx =>
            {
                if (ctx.Message is Pong)
                {
                    tcs.SetResult(true);
                    ctx.Stop(ctx.Self);
                }

                return(Actor.Done);
            }
                    )
                );

            var json     = new JsonMessage("remote_test_messages.Ping", "{ \"message\":\"Hello\"}");
            var envelope = new Proto.MessageEnvelope(json, localActor, Proto.MessageHeader.Empty);

            Remote.SendMessage(remoteActor, envelope, 1);

            logger.LogDebug("sent message");
            logger.LogDebug("awaiting completion");

            await tcs.Task;
            await receivedTerminationTcs.Task;
        }
Exemplo n.º 6
0
        public async Task ReceiveAsync(IContext context)
        {
            switch (context.Message)
            {
            case Started _:
                context.Send(context.Self, "listen");
                break;

            // case ClientHostPIDRequest _:
            //     _logger.LogDebug("Received PID Request");
            //     if (_clientHostPIDResponse != null)
            //     {
            //         _logger.LogDebug("Returning PID Response");
            //         context.Respond(_clientHostPIDResponse);
            //     }
            //     else
            //     {
            //         _pidRequester = context.Sender;
            //     }
            //     //start listening
            //     context.Send(context.Self, "listen");

            //     break;

            case String str:
                if (str != "listen")
                {
                    return;
                }

                //We use a recursive message here to allow errors in this method to be handled by the supervision hierarchy and still receive system messages

                _logger.LogDebug("Awaiting Message Batch");
                if (!await _responseStream.MoveNext(new CancellationToken()))
                {
                    //This is when we are at the end of the stream - Means we received the end of stream signal from the server
                    //Maybe need to throw an exception that can be handled by our supervisor
                    EventStream.Instance.Publish(new EndpointTerminatedEvent());
                    return;
                }

                _logger.LogDebug("Received Message Batch");
                var messageBatch = _responseStream.Current;
                foreach (var envelope in messageBatch.Envelopes)
                {
                    var target = new PID(ProcessRegistry.Instance.Address,
                                         messageBatch.TargetNames[envelope.Target]);

                    var message = Serialization.Deserialize(messageBatch.TypeNames[envelope.TypeId],
                                                            envelope.MessageData, envelope.SerializerId);

                    if (message is ClientHostPIDResponse pidResponse)
                    {
                        _logger.LogDebug("Received PID Response");

                        //TODO: Just set the address and fire off the endpoitnconnectedevent
                        var clientProcessRegistry = (ClientProcessRegistry)ProcessRegistry.Instance;
                        clientProcessRegistry.Address = pidResponse.HostProcess.Address;
                        clientProcessRegistry.BaseId  = pidResponse.HostProcess.Id;


                        context.Send(context.Parent, new EndpointConnectedEvent {
                            Address = pidResponse.HostProcess.Address
                        });

                        context.Send(context.Self, "listen");
                        return;
                    }


                    _logger.LogDebug(
                        $"Opened Envelope from {envelope.Sender} for {target} containing message {message.GetType()}");
                    //todo: Need to convert the headers here
                    var localEnvelope = new Proto.MessageEnvelope(message, envelope.Sender, null);

                    context.Send(target, localEnvelope);
                    context.Send(context.Self, "listen");
                }



                break;
            }
        }
        public override async Task ConnectClient(IAsyncStreamReader <ClientMessageBatch> requestStream,
                                                 IServerStreamWriter <MessageBatch> responseStream, ServerCallContext context)
        {
            _logger.LogDebug($"Spawning Client EndpointWriter");

            _logger.LogDebug($"Request headers count is {context.RequestHeaders.Count} - {context.RequestHeaders.Select(entry => entry.Key + ":" + entry.Value).Aggregate((acc, value) => acc + "," + value)}");
            var clientIdHeader = context.RequestHeaders.FirstOrDefault(entry => entry.Key == "clientid");
            var clientId       = clientIdHeader?.Value;

            if (clientId == null)
            {
                clientId = Guid.NewGuid().ToString();
                _logger.LogWarning($"clientId header is not set - generating random client id {clientId}");
            }


            var clientHostEndpointWriter = await SpawnClientHostEndpointWriter(responseStream, clientId);


            try
            {
                while (await requestStream.MoveNext())
                {
                    var clientMessageBatch = requestStream.Current;

                    var targetAddress = clientMessageBatch.Address;

                    _logger.LogDebug($"Received Batch for {targetAddress}");

                    foreach (var envelope in clientMessageBatch.Batch.Envelopes)
                    {
                        var message = Serialization.Deserialize(clientMessageBatch.Batch.TypeNames[envelope.TypeId],
                                                                envelope.MessageData, envelope.SerializerId);

                        _logger.LogDebug($"Batch Message {message.GetType()}");

                        var target = new PID(targetAddress, clientMessageBatch.Batch.TargetNames[envelope.Target]);


                        _logger.LogDebug($"Target is {target}");



                        //Forward the message to the correct endpoint
                        Proto.MessageHeader header = null;
                        if (envelope.MessageHeader != null)
                        {
                            header = new Proto.MessageHeader(envelope.MessageHeader.HeaderData);
                        }

                        var forwardingEnvelope = new Proto.MessageEnvelope(message, envelope.Sender, header);

                        _logger.LogDebug($"Sending message {message.GetType()} to target {target} from {envelope.Sender}");

                        RootContext.Empty.Send(target, forwardingEnvelope);
                    }
                }

                _logger.LogDebug("Finished Request Stream - stopping connection manager");

                await clientHostEndpointWriter.PoisonAsync();

                _logger.LogDebug("Client Endpoint manager shut down");
            }
            catch (Exception ex)
            {
                _logger.LogCritical(ex, "Exception on Client Host");
                throw ex;
            }
        }