diff --git a/src/core/Akka.Remote.Tests/RemotingSpec.cs b/src/core/Akka.Remote.Tests/RemotingSpec.cs index f6e3dd6255d..544b9d11520 100644 --- a/src/core/Akka.Remote.Tests/RemotingSpec.cs +++ b/src/core/Akka.Remote.Tests/RemotingSpec.cs @@ -11,6 +11,7 @@ using Akka.Actor; using Akka.Actor.Dsl; using Akka.Configuration; +using Akka.Event; using Akka.Remote.Transport; using Akka.Routing; using Akka.TestKit; @@ -651,6 +652,21 @@ await EventFilter.Exception(start: "Discarding oversi }); } + /// + /// Validate that we can accurately log wrapped messages that fail to be delivered + /// + [Fact] + public void Log_Wrapped_messages_that_fail_to_Send() + { + // 2x wrapped message + var wrappedMessage = + new DeadLetter(new ActorSelectionMessage("hit", Array.Empty(), false), TestActor, + TestActor); + + var loggedType = EndpointWriter.LogPossiblyWrappedMessageType(wrappedMessage); + loggedType.Should().Contain("DeadLetter").And.Contain("ActorSelectionMessage").And.Contain("String"); + } + [Fact] public async Task Drop_received_messages_over_payload_size() { diff --git a/src/core/Akka.Remote.Tests/RemotingTerminatorSpecs.cs b/src/core/Akka.Remote.Tests/RemotingTerminatorSpecs.cs index 5d0a0931ceb..03f09a7de67 100644 --- a/src/core/Akka.Remote.Tests/RemotingTerminatorSpecs.cs +++ b/src/core/Akka.Remote.Tests/RemotingTerminatorSpecs.cs @@ -119,9 +119,13 @@ await EventFilter.Exception().ExpectAsync(0, (await associated.Ask(new Identify("foo"), RemainingOrDefault)).MessageId.ShouldBe("foo"); // terminate the DEPLOYED system - Assert.True(await _sys2.Terminate().AwaitWithTimeout(10.Seconds()), "Expected to terminate within 10 seconds, but didn't."); - await ExpectTerminatedAsync(associated); // expect that the remote deployed actor is dead - + await WithinAsync(TimeSpan.FromSeconds(10), async () => + { + var terminationTask = _sys2.Terminate(); // start termination process + await ExpectTerminatedAsync(associated); // expect that the remote deployed actor is dead + Assert.True(await terminationTask.AwaitWithTimeout(RemainingOrDefault), "Expected to terminate within 10 seconds, but didn't."); + }); + // now terminate the DEPLOYER system Assert.True(await Sys.Terminate().AwaitWithTimeout(10.Seconds()), "Expected to terminate within 10 seconds, but didn't."); }); diff --git a/src/core/Akka.Remote/Endpoint.cs b/src/core/Akka.Remote/Endpoint.cs index 28701087ac2..a8db5abcbaf 100644 --- a/src/core/Akka.Remote/Endpoint.cs +++ b/src/core/Akka.Remote/Endpoint.cs @@ -11,6 +11,7 @@ using System.Diagnostics; using System.Linq; using System.Runtime.Serialization; +using System.Text; using System.Threading; using System.Threading.Tasks; using Akka.Actor; @@ -1462,6 +1463,41 @@ private void BecomeWritingOrSendBufferedMessages() } } + /// + /// Unwraps in order to help make it easier to troubleshoot + /// which oversized message was sent. + /// + /// The formatted type string. + /// + /// Internal for testing purposes only. + /// + internal static string LogPossiblyWrappedMessageType(object failedMsg) + { + if (failedMsg is IWrappedMessage wrappedMessage) + { + static void LogWrapped(StringBuilder builder, IWrappedMessage nextMsg) + { + builder.Append($"{nextMsg.GetType()}-->"); + if (nextMsg.Message is IWrappedMessage wrappedAgain) + { + builder.Append('('); + LogWrapped(builder, wrappedAgain); // recursively iterate through all layers of wrapping + builder.Append(')'); + } + else + { + builder.Append(nextMsg.Message.GetType()); + } + } + + var builder = new StringBuilder(); + LogWrapped(builder, wrappedMessage); + return builder.ToString(); + } + + return failedMsg.GetType().ToString(); + } + private bool WriteSend(EndpointManager.Send send) { try @@ -1486,7 +1522,7 @@ private bool WriteSend(EndpointManager.Send send) string.Format("Discarding oversized payload sent to {0}: max allowed size {1} bytes, actual size of encoded {2} was {3} bytes.", send.Recipient, Transport.MaximumPayloadBytes, - send.Message.GetType(), + LogPossiblyWrappedMessageType(send.Message), pdu.Length)); _log.Error(reason, "Transient association error (association remains live)"); return true; @@ -1509,7 +1545,7 @@ private bool WriteSend(EndpointManager.Send send) _log.Error( ex, "Serialization failed for message [{0}]. Transient association error (association remains live)", - send.Message.GetType()); + LogPossiblyWrappedMessageType(send.Message)); return true; } catch (ArgumentException ex) @@ -1517,7 +1553,7 @@ private bool WriteSend(EndpointManager.Send send) _log.Error( ex, "Serializer threw ArgumentException for message type [{0}]. Transient association error (association remains live)", - send.Message.GetType()); + LogPossiblyWrappedMessageType(send.Message)); return true; } catch (EndpointException ex)