From 333ed0feb0418d183a5b616630210b70f395dcff Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Thu, 8 Dec 2022 17:53:41 -0600 Subject: [PATCH] `Exception` serialization support for built-in messages (#6297) * added end to end spec to validate error serialization for remote actor supervision * defined `.proto`s for `Status.Failure` and `Status.Success` * added `Status.,Failure` and `Status.Success` support to the `MiscMessageSerializer` * added tests to `MiscMessageSerializerSpec` * close #3903 (cherry picked from commit 998dcca6039d037be9a380bff5b19b9112db33af) --- .../Serialization/Bugfix3903Spec.cs | 124 +++++ .../MiscMessageSerializerSpec.cs | 26 +- .../Akka.Remote/Configuration/Remote.conf | 2 + .../Serialization/ExceptionSupport.cs | 2 +- .../MessageContainerSerializer.cs | 3 +- .../Serialization/MiscMessageSerializer.cs | 244 +++++++--- .../Serialization/Proto/ContainerFormats.g.cs | 453 +++++++++++++++++- src/protobuf/ContainerFormats.proto | 9 + 8 files changed, 793 insertions(+), 70 deletions(-) create mode 100644 src/core/Akka.Remote.Tests/Serialization/Bugfix3903Spec.cs diff --git a/src/core/Akka.Remote.Tests/Serialization/Bugfix3903Spec.cs b/src/core/Akka.Remote.Tests/Serialization/Bugfix3903Spec.cs new file mode 100644 index 00000000000..65811962fa2 --- /dev/null +++ b/src/core/Akka.Remote.Tests/Serialization/Bugfix3903Spec.cs @@ -0,0 +1,124 @@ +//----------------------------------------------------------------------- +// +// Copyright (C) 2009-2022 Lightbend Inc. +// Copyright (C) 2013-2022 .NET Foundation +// +//----------------------------------------------------------------------- + +using System; +using System.Threading.Tasks; +using Akka.Actor; +using Akka.Configuration; +using Akka.TestKit; +using Akka.Util.Internal; +using Xunit; +using Xunit.Abstractions; +using FluentAssertions; + +namespace Akka.Remote.Tests.Serialization +{ + public class Bugfix3903Spec : AkkaSpec + { + // hocon config enabling akka.remote + private static readonly Config Config = @"akka.actor.provider = remote + akka.remote.dot-netty.tcp.hostname = localhost + akka.remote.dot-netty.tcp.port = 0"; + + public Bugfix3903Spec(ITestOutputHelper outputHelper) : base(Config, outputHelper) + { + } + + #region Internal Types + + // parent actor type that will remotely deploy a child actor type onto a specific address + private class ParentActor : ReceiveActor + { + // message type that includes an Address + public class DeployChild + { + public DeployChild(Address address) + { + Address = address; + } + + public Address Address { get; } + } + + public ParentActor() + { + Receive(s => + { + // props to deploy an EchoActor at the address specified in DeployChild + var props = Props.Create().WithDeploy(new Deploy(new RemoteScope(s.Address))); + var child = Context.ActorOf(props, "child"); + Sender.Tell(child); + }); + } + } + + internal class EchoActor : ReceiveActor + { + public class Fail + { + public static readonly Fail Instance = new Fail(); + private Fail(){} + } + + public EchoActor() + { + // receive message that will cause this actor to fail + Receive(s => + { + throw new ApplicationException("fail"); + }); + ReceiveAny(o => Sender.Tell(o)); + } + } + + #endregion + + // a test where Sys starts a ParentActor and has it remotely deploy an EchoActor onto a second ActorSystem + [Fact] + public async Task ParentActor_should_be_able_to_deploy_EchoActor_to_remote_system() + { + // create a second ActorSystem + var system2 = ActorSystem.Create(Sys.Name, Sys.Settings.Config); + InitializeLogger(system2); + try + { + // create a supervision strategy that will send a message to the TestActor including the exception of the child that failed + var strategy = new OneForOneStrategy(ex => + { + TestActor.Tell(ex); + return Directive.Stop; + }); + + // create a ParentActor in the first ActorSystem + var parent = Sys.ActorOf(Props.Create().WithSupervisorStrategy(strategy), "parent"); + + // have the ParentActor remotely deploy an EchoActor onto the second ActorSystem + var child = await parent + .Ask(new ParentActor.DeployChild( + system2.AsInstanceOf().Provider.DefaultAddress), RemainingOrDefault).ConfigureAwait(false); + + // assert that Child is a remote actor reference + child.Should().BeOfType(); + Watch(child); + + // send a message to the EchoActor and verify that it is received + (await child.Ask("hello", RemainingOrDefault).ConfigureAwait(false)).Should().Be("hello"); + + // cause the child to crash + child.Tell(EchoActor.Fail.Instance); + var exception = ExpectMsg(); + exception.Message.Should().Be("fail"); + ExpectTerminated(child); + } + finally + { + // shut down the second ActorSystem + Shutdown(system2); + } + } + } +} \ No newline at end of file diff --git a/src/core/Akka.Remote.Tests/Serialization/MiscMessageSerializerSpec.cs b/src/core/Akka.Remote.Tests/Serialization/MiscMessageSerializerSpec.cs index 7065028ed99..33e708691a4 100644 --- a/src/core/Akka.Remote.Tests/Serialization/MiscMessageSerializerSpec.cs +++ b/src/core/Akka.Remote.Tests/Serialization/MiscMessageSerializerSpec.cs @@ -76,6 +76,30 @@ public void Can_serialize_IdentifyWithNull() AssertEqual(identify); } + [Theory] + [InlineData(null)] + [InlineData(1)] + [InlineData("hi")] + public void Can_serialize_StatusSuccess(object payload) + { + var success = new Status.Success(payload); + AssertEqual(success); + } + + [Theory] + [InlineData(null)] + [InlineData(1)] + [InlineData("hi")] + public void Can_serialize_StatusFailure(object payload) + { + var success = new Status.Failure(new ApplicationException("foo"),payload); + // can't use AssertEqual here since the Exception data isn't 100% identical after round-trip serialization + var deserialized = AssertAndReturn(success); + deserialized.State.Should().BeEquivalentTo(success.State); + deserialized.Cause.Message.Should().BeEquivalentTo(success.Cause.Message); + deserialized.Cause.Should().BeOfType(success.Cause.GetType()); + } + [Fact] public void Can_serialize_ActorIdentity() { @@ -372,7 +396,7 @@ private T AssertAndReturn(T message) private void AssertEqual(T message) { var deserialized = AssertAndReturn(message); - Assert.Equal(message, deserialized); + deserialized.Should().BeEquivalentTo(message); } } } diff --git a/src/core/Akka.Remote/Configuration/Remote.conf b/src/core/Akka.Remote/Configuration/Remote.conf index 3b593c2f75a..5f1441256ee 100644 --- a/src/core/Akka.Remote/Configuration/Remote.conf +++ b/src/core/Akka.Remote/Configuration/Remote.conf @@ -39,6 +39,8 @@ akka { "Akka.Actor.PoisonPill, Akka" = akka-misc "Akka.Actor.Kill, Akka" = akka-misc "Akka.Actor.PoisonPill, Akka" = akka-misc + "Akka.Actor.Status+Failure, Akka" = akka-misc + "Akka.Actor.Status+Success, Akka" = akka-misc #"Akka.Actor.LocalScope, Akka" = akka-misc "Akka.Actor.RemoteScope, Akka" = akka-misc "Akka.Routing.FromConfig, Akka" = akka-misc diff --git a/src/core/Akka.Remote/Serialization/ExceptionSupport.cs b/src/core/Akka.Remote/Serialization/ExceptionSupport.cs index ba304ceaf00..2b09bde70d9 100644 --- a/src/core/Akka.Remote/Serialization/ExceptionSupport.cs +++ b/src/core/Akka.Remote/Serialization/ExceptionSupport.cs @@ -150,7 +150,7 @@ public Exception ExceptionFromProtoNet(Proto.Msg.ExceptionData proto) return obj; } - private string ValueOrNull(string value) + private static string ValueOrNull(string value) => string.IsNullOrEmpty(value) ? null : value; } } diff --git a/src/core/Akka.Remote/Serialization/MessageContainerSerializer.cs b/src/core/Akka.Remote/Serialization/MessageContainerSerializer.cs index 087501bd2ef..0c140482d2f 100644 --- a/src/core/Akka.Remote/Serialization/MessageContainerSerializer.cs +++ b/src/core/Akka.Remote/Serialization/MessageContainerSerializer.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Runtime.Serialization; using Akka.Actor; -using Akka.Remote.Serialization.Proto.Msg; using Akka.Serialization; using Akka.Util; using Google.Protobuf; @@ -108,7 +107,7 @@ public override object FromBinary(byte[] bytes, Type type) return new ActorSelectionMessage(message, elements); } - private Proto.Msg.Selection BuildPattern(string matcher, Proto.Msg.Selection.Types.PatternType tpe) + private static Proto.Msg.Selection BuildPattern(string matcher, Proto.Msg.Selection.Types.PatternType tpe) { var selection = new Proto.Msg.Selection { Type = tpe }; if (matcher != null) diff --git a/src/core/Akka.Remote/Serialization/MiscMessageSerializer.cs b/src/core/Akka.Remote/Serialization/MiscMessageSerializer.cs index d3e54e48e67..df5b70ae016 100644 --- a/src/core/Akka.Remote/Serialization/MiscMessageSerializer.cs +++ b/src/core/Akka.Remote/Serialization/MiscMessageSerializer.cs @@ -42,10 +42,13 @@ public sealed class MiscMessageSerializer : SerializerWithStringManifest private const string TailChoppingPoolManifest = "ROTCP"; private const string ConsistentHashingPoolManifest = "ROCHP"; private const string RemoteRouterConfigManifest = "RORRC"; + private const string StatusFailureManifest = "STF"; + private const string StatusSuccessManifest = "STS"; - private static readonly byte[] EmptyBytes = {}; + private static readonly byte[] EmptyBytes = Array.Empty(); private readonly WrappedPayloadSupport _payloadSupport; + private readonly ExceptionSupport _exceptionSupport; /// /// Initializes a new instance of the class. @@ -54,84 +57,161 @@ public sealed class MiscMessageSerializer : SerializerWithStringManifest public MiscMessageSerializer(ExtendedActorSystem system) : base(system) { _payloadSupport = new WrappedPayloadSupport(system); + _exceptionSupport = new ExceptionSupport(system); } /// public override byte[] ToBinary(object obj) { - if (obj is Identify identify) return IdentifyToProto(identify); - if (obj is ActorIdentity actorIdentity) return ActorIdentityToProto(actorIdentity); - if (obj is IActorRef actorRef) return ActorRefToProto(actorRef); - if (obj is PoisonPill) return EmptyBytes; - if (obj is Kill) return EmptyBytes; - if (obj is RemoteWatcher.Heartbeat) return EmptyBytes; - if (obj is RemoteWatcher.HeartbeatRsp heartbeatRsp) return HeartbeatRspToProto(heartbeatRsp); - if (obj is LocalScope) return EmptyBytes; - if (obj is RemoteScope remoteScope) return RemoteScopeToProto(remoteScope); - if (obj is Config config) return ConfigToProto(config); - if (obj is FromConfig fromConfig) return FromConfigToProto(fromConfig); - if (obj is DefaultResizer defaultResizer) return DefaultResizerToProto(defaultResizer); - if (obj is RoundRobinPool roundRobinPool) return RoundRobinPoolToProto(roundRobinPool); - if (obj is BroadcastPool broadcastPool) return BroadcastPoolToProto(broadcastPool); - if (obj is RandomPool randomPool) return RandomPoolToProto(randomPool); - if (obj is ScatterGatherFirstCompletedPool scatterPool) return ScatterGatherFirstCompletedPoolToProto(scatterPool); - if (obj is TailChoppingPool tailChoppingPool) return TailChoppingPoolToProto(tailChoppingPool); - if (obj is ConsistentHashingPool hashingPool) return ConsistentHashingPoolToProto(hashingPool); - if (obj is RemoteRouterConfig remoteRouterConfig) return RemoteRouterConfigToProto(remoteRouterConfig); - - throw new ArgumentException($"Cannot serialize object of type [{obj.GetType().TypeQualifiedName()}]"); + switch (obj) + { + case Identify identify: + return IdentifyToProto(identify); + case ActorIdentity actorIdentity: + return ActorIdentityToProto(actorIdentity); + case IActorRef actorRef: + return ActorRefToProto(actorRef); + case PoisonPill _: + case Kill _: + case RemoteWatcher.Heartbeat _: + return EmptyBytes; + case RemoteWatcher.HeartbeatRsp heartbeatRsp: + return HeartbeatRspToProto(heartbeatRsp); + case Status.Success success: + return StatusSuccessToProto(success); + case Status.Failure failure: + return StatusFailureToProto(failure); + case LocalScope _: + return EmptyBytes; + case RemoteScope remoteScope: + return RemoteScopeToProto(remoteScope); + case Config config: + return ConfigToProto(config); + case FromConfig fromConfig: + return FromConfigToProto(fromConfig); + case DefaultResizer defaultResizer: + return DefaultResizerToProto(defaultResizer); + case RoundRobinPool roundRobinPool: + return RoundRobinPoolToProto(roundRobinPool); + case BroadcastPool broadcastPool: + return BroadcastPoolToProto(broadcastPool); + case RandomPool randomPool: + return RandomPoolToProto(randomPool); + case ScatterGatherFirstCompletedPool scatterPool: + return ScatterGatherFirstCompletedPoolToProto(scatterPool); + case TailChoppingPool tailChoppingPool: + return TailChoppingPoolToProto(tailChoppingPool); + case ConsistentHashingPool hashingPool: + return ConsistentHashingPoolToProto(hashingPool); + case RemoteRouterConfig remoteRouterConfig: + return RemoteRouterConfigToProto(remoteRouterConfig); + default: + throw new ArgumentException($"Cannot serialize object of type [{obj.GetType().TypeQualifiedName()}]"); + } } /// public override string Manifest(object obj) { - if (obj is Identify) return IdentifyManifest; - if (obj is ActorIdentity) return ActorIdentityManifest; - if (obj is IActorRef) return ActorRefManifest; - if (obj is PoisonPill) return PoisonPillManifest; - if (obj is Kill) return KillManifest; - if (obj is RemoteWatcher.Heartbeat) return RemoteWatcherHearthbeatManifest; - if (obj is RemoteWatcher.HeartbeatRsp) return RemoteWatcherHearthbeatRspManifest; - if (obj is LocalScope) return LocalScopeManifest; - if (obj is RemoteScope) return RemoteScopeManifest; - if (obj is Config) return ConfigManifest; - if (obj is FromConfig) return FromConfigManifest; - if (obj is DefaultResizer) return DefaultResizerManifest; - if (obj is RoundRobinPool) return RoundRobinPoolManifest; - if (obj is BroadcastPool) return BroadcastPoolManifest; - if (obj is RandomPool) return RandomPoolManifest; - if (obj is ScatterGatherFirstCompletedPool) return ScatterGatherPoolManifest; - if (obj is TailChoppingPool) return TailChoppingPoolManifest; - if (obj is ConsistentHashingPool) return ConsistentHashingPoolManifest; - if (obj is RemoteRouterConfig) return RemoteRouterConfigManifest; - - throw new ArgumentException($"Cannot deserialize object of type [{obj.GetType().TypeQualifiedName()}]"); + switch (obj) + { + case Identify _: + return IdentifyManifest; + case ActorIdentity _: + return ActorIdentityManifest; + case IActorRef _: + return ActorRefManifest; + case PoisonPill _: + return PoisonPillManifest; + case Kill _: + return KillManifest; + case RemoteWatcher.Heartbeat _: + return RemoteWatcherHearthbeatManifest; + case RemoteWatcher.HeartbeatRsp _: + return RemoteWatcherHearthbeatRspManifest; + case Status.Success _: + return StatusSuccessManifest; + case Status.Failure _: + return StatusFailureManifest; + case LocalScope _: + return LocalScopeManifest; + case RemoteScope _: + return RemoteScopeManifest; + case Config _: + return ConfigManifest; + case FromConfig _: + return FromConfigManifest; + case DefaultResizer _: + return DefaultResizerManifest; + case RoundRobinPool _: + return RoundRobinPoolManifest; + case BroadcastPool _: + return BroadcastPoolManifest; + case RandomPool _: + return RandomPoolManifest; + case ScatterGatherFirstCompletedPool _: + return ScatterGatherPoolManifest; + case TailChoppingPool _: + return TailChoppingPoolManifest; + case ConsistentHashingPool _: + return ConsistentHashingPoolManifest; + case RemoteRouterConfig _: + return RemoteRouterConfigManifest; + default: + throw new ArgumentException($"Cannot deserialize object of type [{obj.GetType().TypeQualifiedName()}]"); + } } /// public override object FromBinary(byte[] bytes, string manifest) { - if (manifest == IdentifyManifest) return IdentifyFromProto(bytes); - if (manifest == ActorIdentityManifest) return ActorIdentityFromProto(bytes); - if (manifest == ActorRefManifest) return ActorRefFromProto(bytes); - if (manifest == PoisonPillManifest) return PoisonPill.Instance; - if (manifest == KillManifest) return Kill.Instance; - if (manifest == RemoteWatcherHearthbeatManifest) return RemoteWatcher.Heartbeat.Instance; - if (manifest == RemoteWatcherHearthbeatRspManifest) return HearthbeatRspFromProto(bytes); - if (manifest == LocalScopeManifest) return LocalScope.Instance; - if (manifest == RemoteScopeManifest) return RemoteScopeFromProto(bytes); - if (manifest == ConfigManifest) return ConfigFromProto(bytes); - if (manifest == FromConfigManifest) return FromConfigFromProto(bytes); - if (manifest == DefaultResizerManifest) return DefaultResizerFromProto(bytes); - if (manifest == RoundRobinPoolManifest) return RoundRobinPoolFromProto(bytes); - if (manifest == BroadcastPoolManifest) return BroadcastPoolFromProto(bytes); - if (manifest == RandomPoolManifest) return RandomPoolFromProto(bytes); - if (manifest == ScatterGatherPoolManifest) return ScatterGatherFirstCompletedPoolFromProto(bytes); - if (manifest == TailChoppingPoolManifest) return TailChoppingPoolFromProto(bytes); - if (manifest == ConsistentHashingPoolManifest) return ConsistentHashingPoolFromProto(bytes); - if (manifest == RemoteRouterConfigManifest) return RemoteRouterConfigFromProto(bytes); - - throw new SerializationException($"Unimplemented deserialization of message with manifest [{manifest}] in [{nameof(MiscMessageSerializer)}]"); + switch (manifest) + { + case IdentifyManifest: + return IdentifyFromProto(bytes); + case ActorIdentityManifest: + return ActorIdentityFromProto(bytes); + case ActorRefManifest: + return ActorRefFromProto(bytes); + case PoisonPillManifest: + return PoisonPill.Instance; + case KillManifest: + return Kill.Instance; + case RemoteWatcherHearthbeatManifest: + return RemoteWatcher.Heartbeat.Instance; + case RemoteWatcherHearthbeatRspManifest: + return HearthbeatRspFromProto(bytes); + case StatusSuccessManifest: + return StatusSuccessFromProto(bytes); + case StatusFailureManifest: + return StatusFailureFromProto(bytes); + case LocalScopeManifest: + return LocalScope.Instance; + case RemoteScopeManifest: + return RemoteScopeFromProto(bytes); + case ConfigManifest: + return ConfigFromProto(bytes); + case FromConfigManifest: + return FromConfigFromProto(bytes); + case DefaultResizerManifest: + return DefaultResizerFromProto(bytes); + case RoundRobinPoolManifest: + return RoundRobinPoolFromProto(bytes); + case BroadcastPoolManifest: + return BroadcastPoolFromProto(bytes); + case RandomPoolManifest: + return RandomPoolFromProto(bytes); + case ScatterGatherPoolManifest: + return ScatterGatherFirstCompletedPoolFromProto(bytes); + case TailChoppingPoolManifest: + return TailChoppingPoolFromProto(bytes); + case ConsistentHashingPoolManifest: + return ConsistentHashingPoolFromProto(bytes); + case RemoteRouterConfigManifest: + return RemoteRouterConfigFromProto(bytes); + default: + throw new SerializationException($"Unimplemented deserialization of message with manifest [{manifest}] in [{nameof(MiscMessageSerializer)}]"); + } } // @@ -206,6 +286,42 @@ private RemoteWatcher.HeartbeatRsp HearthbeatRspFromProto(byte[] bytes) var message = Proto.Msg.RemoteWatcherHeartbeatResponse.Parser.ParseFrom(bytes); return new RemoteWatcher.HeartbeatRsp((int)message.Uid); } + + // + // Status.Success + // + + private byte[] StatusSuccessToProto(Status.Success success) + { + var message = new Proto.Msg.StatusSuccess(); + message.Status = _payloadSupport.PayloadToProto(success.Status); + return message.ToByteArray(); + } + + private Status.Success StatusSuccessFromProto(byte[] bytes) + { + var message = Proto.Msg.StatusSuccess.Parser.ParseFrom(bytes); + return new Status.Success(_payloadSupport.PayloadFrom(message.Status)); + } + + // + // Status.Failure + // + + private byte[] StatusFailureToProto(Status.Failure failure) + { + var message = new Proto.Msg.StatusFailure(); + message.Cause = _exceptionSupport.ExceptionToProto(failure.Cause); + message.State = _payloadSupport.PayloadToProto(failure.State); + return message.ToByteArray(); + } + + private Status.Failure StatusFailureFromProto(byte[] bytes) + { + var message = Proto.Msg.StatusFailure.Parser.ParseFrom(bytes); + var payload = _payloadSupport.PayloadFrom(message.State); + return new Status.Failure(_exceptionSupport.ExceptionFromProto(message.Cause), payload); + } // // RemoteScope diff --git a/src/core/Akka.Remote/Serialization/Proto/ContainerFormats.g.cs b/src/core/Akka.Remote/Serialization/Proto/ContainerFormats.g.cs index 5ca35abaf08..b4d726a1fcf 100644 --- a/src/core/Akka.Remote/Serialization/Proto/ContainerFormats.g.cs +++ b/src/core/Akka.Remote/Serialization/Proto/ContainerFormats.g.cs @@ -49,7 +49,12 @@ static ContainerFormatsReflection() { "MkQuQWtrYS5SZW1vdGUuU2VyaWFsaXphdGlvbi5Qcm90by5Nc2cuRXhjZXB0", "aW9uRGF0YS5DdXN0b21GaWVsZHNFbnRyeRphChFDdXN0b21GaWVsZHNFbnRy", "eRILCgNrZXkYASABKAkSOwoFdmFsdWUYAiABKAsyLC5Ba2thLlJlbW90ZS5T", - "ZXJpYWxpemF0aW9uLlByb3RvLk1zZy5QYXlsb2FkOgI4AWIGcHJvdG8z")); + "ZXJpYWxpemF0aW9uLlByb3RvLk1zZy5QYXlsb2FkOgI4ASJNCg1TdGF0dXNT", + "dWNjZXNzEjwKBnN0YXR1cxgBIAEoCzIsLkFra2EuUmVtb3RlLlNlcmlhbGl6", + "YXRpb24uUHJvdG8uTXNnLlBheWxvYWQijwEKDVN0YXR1c0ZhaWx1cmUSQQoF", + "Y2F1c2UYASABKAsyMi5Ba2thLlJlbW90ZS5TZXJpYWxpemF0aW9uLlByb3Rv", + "Lk1zZy5FeGNlcHRpb25EYXRhEjsKBXN0YXRlGAIgASgLMiwuQWtrYS5SZW1v", + "dGUuU2VyaWFsaXphdGlvbi5Qcm90by5Nc2cuUGF5bG9hZGIGcHJvdG8z")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { @@ -61,7 +66,9 @@ static ContainerFormatsReflection() { new pbr::GeneratedClrTypeInfo(typeof(global::Akka.Remote.Serialization.Proto.Msg.Identify), global::Akka.Remote.Serialization.Proto.Msg.Identify.Parser, new[]{ "MessageId" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Akka.Remote.Serialization.Proto.Msg.ActorIdentity), global::Akka.Remote.Serialization.Proto.Msg.ActorIdentity.Parser, new[]{ "CorrelationId", "Path" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Akka.Remote.Serialization.Proto.Msg.RemoteWatcherHeartbeatResponse), global::Akka.Remote.Serialization.Proto.Msg.RemoteWatcherHeartbeatResponse.Parser, new[]{ "Uid" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Akka.Remote.Serialization.Proto.Msg.ExceptionData), global::Akka.Remote.Serialization.Proto.Msg.ExceptionData.Parser, new[]{ "TypeName", "Message", "StackTrace", "Source", "InnerException", "CustomFields" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { null, }) + new pbr::GeneratedClrTypeInfo(typeof(global::Akka.Remote.Serialization.Proto.Msg.ExceptionData), global::Akka.Remote.Serialization.Proto.Msg.ExceptionData.Parser, new[]{ "TypeName", "Message", "StackTrace", "Source", "InnerException", "CustomFields" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { null, }), + new pbr::GeneratedClrTypeInfo(typeof(global::Akka.Remote.Serialization.Proto.Msg.StatusSuccess), global::Akka.Remote.Serialization.Proto.Msg.StatusSuccess.Parser, new[]{ "Status" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Akka.Remote.Serialization.Proto.Msg.StatusFailure), global::Akka.Remote.Serialization.Proto.Msg.StatusFailure.Parser, new[]{ "Cause", "State" }, null, null, null, null) })); } #endregion @@ -2288,6 +2295,448 @@ public void MergeFrom(pb::CodedInputStream input) { } + internal sealed partial class StatusSuccess : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StatusSuccess()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Akka.Remote.Serialization.Proto.Msg.ContainerFormatsReflection.Descriptor.MessageTypes[9]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public StatusSuccess() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public StatusSuccess(StatusSuccess other) : this() { + status_ = other.status_ != null ? other.status_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public StatusSuccess Clone() { + return new StatusSuccess(this); + } + + /// Field number for the "status" field. + public const int StatusFieldNumber = 1; + private global::Akka.Remote.Serialization.Proto.Msg.Payload status_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Akka.Remote.Serialization.Proto.Msg.Payload Status { + get { return status_; } + set { + status_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as StatusSuccess); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(StatusSuccess other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Status, other.Status)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (status_ != null) hash ^= Status.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (status_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Status); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (status_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Status); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (status_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Status); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(StatusSuccess other) { + if (other == null) { + return; + } + if (other.status_ != null) { + if (status_ == null) { + Status = new global::Akka.Remote.Serialization.Proto.Msg.Payload(); + } + Status.MergeFrom(other.Status); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (status_ == null) { + Status = new global::Akka.Remote.Serialization.Proto.Msg.Payload(); + } + input.ReadMessage(Status); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (status_ == null) { + Status = new global::Akka.Remote.Serialization.Proto.Msg.Payload(); + } + input.ReadMessage(Status); + break; + } + } + } + } + #endif + + } + + internal sealed partial class StatusFailure : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StatusFailure()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Akka.Remote.Serialization.Proto.Msg.ContainerFormatsReflection.Descriptor.MessageTypes[10]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public StatusFailure() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public StatusFailure(StatusFailure other) : this() { + cause_ = other.cause_ != null ? other.cause_.Clone() : null; + state_ = other.state_ != null ? other.state_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public StatusFailure Clone() { + return new StatusFailure(this); + } + + /// Field number for the "cause" field. + public const int CauseFieldNumber = 1; + private global::Akka.Remote.Serialization.Proto.Msg.ExceptionData cause_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Akka.Remote.Serialization.Proto.Msg.ExceptionData Cause { + get { return cause_; } + set { + cause_ = value; + } + } + + /// Field number for the "state" field. + public const int StateFieldNumber = 2; + private global::Akka.Remote.Serialization.Proto.Msg.Payload state_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Akka.Remote.Serialization.Proto.Msg.Payload State { + get { return state_; } + set { + state_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as StatusFailure); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(StatusFailure other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Cause, other.Cause)) return false; + if (!object.Equals(State, other.State)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (cause_ != null) hash ^= Cause.GetHashCode(); + if (state_ != null) hash ^= State.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (cause_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Cause); + } + if (state_ != null) { + output.WriteRawTag(18); + output.WriteMessage(State); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (cause_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Cause); + } + if (state_ != null) { + output.WriteRawTag(18); + output.WriteMessage(State); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (cause_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Cause); + } + if (state_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(State); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(StatusFailure other) { + if (other == null) { + return; + } + if (other.cause_ != null) { + if (cause_ == null) { + Cause = new global::Akka.Remote.Serialization.Proto.Msg.ExceptionData(); + } + Cause.MergeFrom(other.Cause); + } + if (other.state_ != null) { + if (state_ == null) { + State = new global::Akka.Remote.Serialization.Proto.Msg.Payload(); + } + State.MergeFrom(other.State); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (cause_ == null) { + Cause = new global::Akka.Remote.Serialization.Proto.Msg.ExceptionData(); + } + input.ReadMessage(Cause); + break; + } + case 18: { + if (state_ == null) { + State = new global::Akka.Remote.Serialization.Proto.Msg.Payload(); + } + input.ReadMessage(State); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (cause_ == null) { + Cause = new global::Akka.Remote.Serialization.Proto.Msg.ExceptionData(); + } + input.ReadMessage(Cause); + break; + } + case 18: { + if (state_ == null) { + State = new global::Akka.Remote.Serialization.Proto.Msg.Payload(); + } + input.ReadMessage(State); + break; + } + } + } + } + #endif + + } + #endregion } diff --git a/src/protobuf/ContainerFormats.proto b/src/protobuf/ContainerFormats.proto index 0007ca45e4e..edef1ef90d5 100644 --- a/src/protobuf/ContainerFormats.proto +++ b/src/protobuf/ContainerFormats.proto @@ -70,3 +70,12 @@ message ExceptionData { ExceptionData innerException = 5; map customFields = 6; } + +message StatusSuccess{ + Payload status = 1; +} + +message StatusFailure{ + ExceptionData cause = 1; + Payload state = 2; +} \ No newline at end of file