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; }
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); }); }
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; }
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; } }