You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/05/05 09:45:37 UTC

[26/50] [abbrv] ignite git commit: IGNITE-5135 .NET: Improve remote error propagation

IGNITE-5135 .NET: Improve remote error propagation

This closes #1899


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/97c2a3ce
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/97c2a3ce
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/97c2a3ce

Branch: refs/heads/ignite-5009
Commit: 97c2a3ce0f1d0a6f30e288bee8102cb107f46ee6
Parents: ed72663
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Wed May 3 16:45:52 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Wed May 3 16:45:52 2017 +0300

----------------------------------------------------------------------
 .../Compute/BinarizableClosureTaskTest.cs       |  10 +-
 .../Compute/ComputeApiTest.cs                   |  26 +++++
 .../Compute/FailoverTaskSelfTest.cs             |  46 +++-----
 .../Compute/IgniteExceptionTaskSelfTest.cs      | 105 ++++++++++---------
 .../Compute/SerializableClosureTaskTest.cs      |  30 +++---
 .../Log/CustomLoggerTest.cs                     |   3 +-
 .../Compute/ComputeTaskAdapter.cs               |   4 +-
 .../Closure/ComputeAbstractClosureTask.cs       |   3 +-
 .../Apache.Ignite.Core/Impl/Compute/Compute.cs  |  17 +++
 .../Impl/Compute/ComputeJobHolder.cs            |   3 +-
 .../Impl/Compute/ComputeTaskHolder.cs           |   8 +-
 11 files changed, 149 insertions(+), 106 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/BinarizableClosureTaskTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/BinarizableClosureTaskTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/BinarizableClosureTaskTest.cs
index 051917b..e8952bf 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/BinarizableClosureTaskTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/BinarizableClosureTaskTest.cs
@@ -56,9 +56,9 @@ namespace Apache.Ignite.Core.Tests.Compute
         {
             Assert.IsTrue(res != null);
 
-            BinarizableResult res0 = res as BinarizableResult;
+            var res0 = res as BinarizableResult;
 
-            Assert.IsTrue(res0 != null);
+            Assert.IsNotNull(res0);
             Assert.AreEqual(1, res0.Res);
         }
 
@@ -72,9 +72,11 @@ namespace Apache.Ignite.Core.Tests.Compute
             if (aggregate != null)
                 err = aggregate.InnerException;
 
-            BinarizableException err0 = err as BinarizableException;
+            Assert.IsNotNull(err);
 
-            Assert.IsTrue(err0 != null);
+            var err0 = err.InnerException as BinarizableException;
+
+            Assert.IsNotNull(err0);
             Assert.AreEqual(ErrMsg, err0.Msg);
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
index 02eb266..e403d93 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/ComputeApiTest.cs
@@ -1265,6 +1265,22 @@ namespace Apache.Ignite.Core.Tests.Compute
             Assert.Throws<BinaryObjectException>(
                 () => _grid1.GetCompute().Execute<NetSimpleJobArgument, NetSimpleJobResult, NetSimpleTaskResult>(
                     typeof (NetSimpleTask), new NetSimpleJobArgument(-1)));
+
+            // Local.
+            var ex = Assert.Throws<IgniteException>(() =>
+                _grid1.GetCluster().ForLocal().GetCompute().Broadcast(new ExceptionalComputeAction()));
+
+            Assert.AreEqual("Compute job has failed on local node, examine InnerException for details.", ex.Message);
+            Assert.IsNotNull(ex.InnerException);
+            Assert.AreEqual(ExceptionalComputeAction.ErrorText, ex.InnerException.Message);
+
+            // Remote.
+            ex = Assert.Throws<IgniteException>(() =>
+                _grid1.GetCluster().ForRemotes().GetCompute().Broadcast(new ExceptionalComputeAction()));
+
+            Assert.AreEqual("Compute job has failed on remote node, examine InnerException for details.", ex.Message);
+            Assert.IsNotNull(ex.InnerException);
+            Assert.AreEqual(ExceptionalComputeAction.ErrorText, ex.InnerException.Message);
         }
 
         /// <summary>
@@ -1465,6 +1481,16 @@ namespace Apache.Ignite.Core.Tests.Compute
         }
     }
 
+    class ExceptionalComputeAction : IComputeAction
+    {
+        public const string ErrorText = "Expected user exception";
+
+        public void Invoke()
+        {
+            throw new OverflowException(ErrorText);
+        }
+    }
+
     interface IUserInterface<out T>
     {
         T Invoke();

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/FailoverTaskSelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/FailoverTaskSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/FailoverTaskSelfTest.cs
index 9eb87c0..3193e46 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/FailoverTaskSelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/FailoverTaskSelfTest.cs
@@ -19,6 +19,7 @@ namespace Apache.Ignite.Core.Tests.Compute
 {
     using System;
     using System.Collections.Generic;
+    using System.Linq;
     using Apache.Ignite.Core.Cluster;
     using Apache.Ignite.Core.Compute;
     using Apache.Ignite.Core.Resource;
@@ -112,45 +113,28 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// Test task.
         /// </summary>
-        public class TestTask : ComputeTaskAdapter<Tuple<bool, bool>, int, int>
+        private class TestTask : ComputeTaskAdapter<Tuple<bool, bool>, int, int>
         {
             /** <inheritDoc /> */
-            override public IDictionary<IComputeJob<int>, IClusterNode> Map(IList<IClusterNode> subgrid, Tuple<bool, bool> arg)
+            public override IDictionary<IComputeJob<int>, IClusterNode> Map(IList<IClusterNode> subgrid, 
+                Tuple<bool, bool> arg)
             {
                 Assert.AreEqual(2, subgrid.Count);
 
-                Tuple<bool, bool> t = arg;
+                var serializable = arg.Item1;
+                var local = arg.Item2;
 
-                bool serializable = t.Item1;
-                bool local = t.Item2;
+                var job = serializable 
+                    ? (IComputeJob<int>) new TestSerializableJob() 
+                    :  new TestBinarizableJob();
 
-                IDictionary<IComputeJob<int>, IClusterNode> jobs = new Dictionary<IComputeJob<int>, IClusterNode>();
+                var node = subgrid.Single(x => x.IsLocal == local);
 
-                IComputeJob<int> job;
-
-                if (serializable)
-                    job = new TestSerializableJob();
-                else
-                    job = new TestBinarizableJob();
-
-                foreach (IClusterNode node in subgrid) {
-                    bool add = local ? node.IsLocal : !node.IsLocal;
-
-                    if (add)
-                    {
-                        jobs.Add(job, node);
-
-                        break;
-                    }
-                }
-
-                Assert.AreEqual(1, jobs.Count);
-
-                return jobs;
+                return new Dictionary<IComputeJob<int>, IClusterNode> {{job, node}};
             }
 
             /** <inheritDoc /> */
-            override public int Reduce(IList<IComputeJobResult<int>> results)
+            public override int Reduce(IList<IComputeJobResult<int>> results)
             {
                 Assert.AreEqual(1, results.Count);
 
@@ -162,7 +146,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         ///
         /// </summary>
         [Serializable]
-        class TestClosure : IComputeFunc<int>
+        private class TestClosure : IComputeFunc<int>
         {
             [InstanceResource]
             private readonly IIgnite _grid = null;
@@ -178,7 +162,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         ///
         /// </summary>
         [Serializable]
-        class TestSerializableJob : IComputeJob<int>
+        private class TestSerializableJob : IComputeJob<int>
         {
             [InstanceResource]
             private readonly IIgnite _grid = null;
@@ -199,7 +183,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         ///
         /// </summary>
-        class TestBinarizableJob : IComputeJob<int>
+        private class TestBinarizableJob : IComputeJob<int>
         {
             [InstanceResource]
             private readonly IIgnite _grid = null;

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs
index 21cd263..2f9f6b4 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/IgniteExceptionTaskSelfTest.cs
@@ -34,10 +34,10 @@ namespace Apache.Ignite.Core.Tests.Compute
     public class IgniteExceptionTaskSelfTest : AbstractTaskTest
     {
         /** Error mode. */
-        public static ErrorMode Mode;
+        private static ErrorMode _mode;
 
         /** Observed job errors. */
-        public static readonly ICollection<Exception> JobErrs = new List<Exception>();
+        private static readonly ICollection<Exception> JobErrs = new List<Exception>();
 
         /// <summary>
         /// Constructor.
@@ -56,7 +56,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestMapError()
         {
-            Mode = ErrorMode.MapErr;
+            _mode = ErrorMode.MapErr;
 
             GoodException e = ExecuteWithError() as GoodException;
 
@@ -71,7 +71,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestMapNotMarshalableError()
         {
-            Mode = ErrorMode.MapErrNotMarshalable;
+            _mode = ErrorMode.MapErrNotMarshalable;
 
             BadException e = ExecuteWithError() as BadException;
 
@@ -86,7 +86,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestMapNotMarshalableJob()
         {
-            Mode = ErrorMode.MapJobNotMarshalable;
+            _mode = ErrorMode.MapJobNotMarshalable;
 
             Assert.IsInstanceOf<BinaryObjectException>(ExecuteWithError());
         }
@@ -97,15 +97,16 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestLocalJobError()
         {
-            Mode = ErrorMode.LocJobErr;
+            _mode = ErrorMode.LocJobErr;
 
             int res = Execute();
 
             Assert.AreEqual(1, res);
 
             Assert.AreEqual(4, JobErrs.Count);
-            Assert.IsNotNull(JobErrs.First() as GoodException);
-            Assert.AreEqual(ErrorMode.LocJobErr, ((GoodException) JobErrs.First()).Mode);
+            var goodEx = JobErrs.First().InnerException as GoodException;
+            Assert.IsNotNull(goodEx);
+            Assert.AreEqual(ErrorMode.LocJobErr, goodEx.Mode);
         }
 
         /// <summary>
@@ -114,14 +115,14 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestLocalJobErrorNotMarshalable()
         {
-            Mode = ErrorMode.LocJobErrNotMarshalable;
+            _mode = ErrorMode.LocJobErrNotMarshalable;
 
             int res = Execute();
 
             Assert.AreEqual(1, res);
 
             Assert.AreEqual(4, JobErrs.Count);
-            Assert.IsNotNull(JobErrs.First() as BadException); // Local job exception is not marshalled.
+            Assert.IsInstanceOf<BadException>(JobErrs.First().InnerException); // Local job exception is not marshalled.
         }
 
         /// <summary>
@@ -130,7 +131,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestLocalJobResultNotMarshalable()
         {
-            Mode = ErrorMode.LocJobResNotMarshalable;
+            _mode = ErrorMode.LocJobResNotMarshalable;
 
             int res = Execute();
 
@@ -145,7 +146,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestRemoteJobError()
         {
-            Mode = ErrorMode.RmtJobErr;
+            _mode = ErrorMode.RmtJobErr;
 
             int res = Execute();
 
@@ -153,9 +154,10 @@ namespace Apache.Ignite.Core.Tests.Compute
 
             Assert.AreEqual(4, JobErrs.Count);
 
-            Assert.IsNotNull(JobErrs.ElementAt(0) as GoodException);
+            var goodEx = JobErrs.First().InnerException as GoodException;
+            Assert.IsNotNull(goodEx);
 
-            Assert.AreEqual(ErrorMode.RmtJobErr, ((GoodException) JobErrs.ElementAt(0)).Mode);
+            Assert.AreEqual(ErrorMode.RmtJobErr, goodEx.Mode);
         }
 
         /// <summary>
@@ -164,7 +166,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestRemoteJobErrorNotMarshalable()
         {
-            Mode = ErrorMode.RmtJobErrNotMarshalable;
+            _mode = ErrorMode.RmtJobErrNotMarshalable;
 
             Assert.Throws<SerializationException>(() => Execute());
         }
@@ -175,7 +177,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestRemoteJobResultNotMarshalable()
         {
-            Mode = ErrorMode.RmtJobResNotMarshalable;
+            _mode = ErrorMode.RmtJobResNotMarshalable;
 
             int res = Execute();
 
@@ -192,7 +194,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestLocalResultError()
         {
-            Mode = ErrorMode.LocResErr;
+            _mode = ErrorMode.LocResErr;
 
             GoodException e = ExecuteWithError() as GoodException;
 
@@ -207,7 +209,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestLocalResultErrorNotMarshalable()
         {
-            Mode = ErrorMode.LocResErrNotMarshalable;
+            _mode = ErrorMode.LocResErrNotMarshalable;
 
             BadException e = ExecuteWithError() as BadException;
 
@@ -222,7 +224,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestRemoteResultError()
         {
-            Mode = ErrorMode.RmtResErr;
+            _mode = ErrorMode.RmtResErr;
 
             GoodException e = ExecuteWithError() as GoodException;
 
@@ -237,7 +239,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestRemoteResultErrorNotMarshalable()
         {
-            Mode = ErrorMode.RmtResErrNotMarshalable;
+            _mode = ErrorMode.RmtResErrNotMarshalable;
 
             BadException e = ExecuteWithError() as BadException;
 
@@ -252,7 +254,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestReduceError()
         {
-            Mode = ErrorMode.ReduceErr;
+            _mode = ErrorMode.ReduceErr;
 
             GoodException e = ExecuteWithError() as GoodException;
 
@@ -267,7 +269,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestReduceErrorNotMarshalable()
         {
-            Mode = ErrorMode.ReduceErrNotMarshalable;
+            _mode = ErrorMode.ReduceErrNotMarshalable;
 
             BadException e = ExecuteWithError() as BadException;
 
@@ -282,7 +284,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Test]
         public void TestReduceResultNotMarshalable()
         {
-            Mode = ErrorMode.ReduceResNotMarshalable;
+            _mode = ErrorMode.ReduceResNotMarshalable;
 
             int res = Execute();
 
@@ -326,7 +328,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// Error modes.
         /// </summary>
-        public enum ErrorMode
+        private enum ErrorMode
         {
             /** Error during map step. */
             MapErr,
@@ -392,7 +394,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             /** <inheritDoc /> */
             public IDictionary<IComputeJob<object>, IClusterNode> Map(IList<IClusterNode> subgrid, object arg)
             {
-                switch (Mode)
+                switch (_mode)
                 {
                     case ErrorMode.MapErr:
                         throw new GoodException(ErrorMode.MapErr);
@@ -424,16 +426,19 @@ namespace Apache.Ignite.Core.Tests.Compute
             public ComputeJobResultPolicy OnResult(IComputeJobResult<object> res, IList<IComputeJobResult<object>> rcvd)
             {
                 if (res.Exception != null)
+                {
                     JobErrs.Add(res.Exception);
+                }
                 else
                 {
                     object res0 = res.Data;
 
-                    bool rmt = res0 is GoodJobResult ? ((GoodJobResult)res0).Rmt : ((BadJobResult)res0).Rmt;
+                    var result = res0 as GoodJobResult;
+                    bool rmt = result != null ? result.Rmt : ((BadJobResult) res0).Rmt;
 
                     if (rmt)
                     {
-                        switch (Mode)
+                        switch (_mode)
                         {
                             case ErrorMode.RmtResErr:
                                 throw new GoodException(ErrorMode.RmtResErr);
@@ -444,7 +449,7 @@ namespace Apache.Ignite.Core.Tests.Compute
                     }
                     else
                     {
-                        switch (Mode)
+                        switch (_mode)
                         {
                             case ErrorMode.LocResErr:
                                 throw new GoodException(ErrorMode.LocResErr);
@@ -463,7 +468,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             /** <inheritDoc /> */
             public object Reduce(IList<IComputeJobResult<object>> results)
             {
-                switch (Mode)
+                switch (_mode)
                 {
                     case ErrorMode.ReduceErr:
                         throw new GoodException(ErrorMode.ReduceErr);
@@ -483,10 +488,10 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// 
         /// </summary>
         [Serializable]
-        public class GoodJob : IComputeJob<object>
+        private class GoodJob : IComputeJob<object>, ISerializable
         {
             /** Whether the job is remote. */
-            private bool _rmt;
+            private readonly bool _rmt;
 
             /// <summary>
             /// 
@@ -502,7 +507,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             /// </summary>
             /// <param name="info"></param>
             /// <param name="context"></param>
-            public GoodJob(SerializationInfo info, StreamingContext context)
+            protected GoodJob(SerializationInfo info, StreamingContext context)
             {
                 _rmt = info.GetBoolean("rmt");
             }
@@ -518,7 +523,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             {
                 if (_rmt)
                 {
-                    switch (Mode)
+                    switch (_mode)
                     {
                         case ErrorMode.RmtJobErr:
                             throw new GoodException(ErrorMode.RmtJobErr);
@@ -532,7 +537,7 @@ namespace Apache.Ignite.Core.Tests.Compute
                 }
                 else
                 {
-                    switch (Mode)
+                    switch (_mode)
                     {
                         case ErrorMode.LocJobErr:
                             throw new GoodException(ErrorMode.LocJobErr);
@@ -558,7 +563,7 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// 
         /// </summary>
-        public class BadJob : IComputeJob<object>, IBinarizable
+        private class BadJob : IComputeJob<object>, IBinarizable
         {
             [InstanceResource]
 
@@ -591,10 +596,10 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// 
         /// </summary>
         [Serializable]
-        public class GoodJobResult
+        private class GoodJobResult : ISerializable
         {
             /** */
-            public bool Rmt;
+            public readonly bool Rmt;
             
             /// <summary>
             /// 
@@ -610,7 +615,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             /// </summary>
             /// <param name="info"></param>
             /// <param name="context"></param>
-            public GoodJobResult(SerializationInfo info, StreamingContext context)
+            protected GoodJobResult(SerializationInfo info, StreamingContext context)
             {
                 Rmt = info.GetBoolean("rmt");
             }
@@ -625,10 +630,10 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// 
         /// </summary>
-        public class BadJobResult : IBinarizable
+        private class BadJobResult : IBinarizable
         {
             /** */
-            public bool Rmt;
+            public readonly bool Rmt;
 
             /// <summary>
             /// 
@@ -656,10 +661,10 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// 
         /// </summary>
         [Serializable]
-        public class GoodTaskResult
+        private class GoodTaskResult : ISerializable
         {
             /** */
-            public int Res;
+            public readonly int Res;
 
             /// <summary>
             /// 
@@ -675,7 +680,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             /// </summary>
             /// <param name="info"></param>
             /// <param name="context"></param>
-            public GoodTaskResult(SerializationInfo info, StreamingContext context)
+            protected GoodTaskResult(SerializationInfo info, StreamingContext context)
             {
                 Res = info.GetInt32("res");
             }
@@ -690,10 +695,10 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// 
         /// </summary>
-        public class BadTaskResult
+        private class BadTaskResult
         {
             /** */
-            public int Res;
+            public readonly int Res;
 
             /// <summary>
             /// 
@@ -709,10 +714,10 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// Marshalable exception.
         /// </summary>
         [Serializable]
-        public class GoodException : Exception
+        private class GoodException : Exception
         {
             /** */
-            public ErrorMode Mode;
+            public readonly ErrorMode Mode;
             
             /// <summary>
             /// 
@@ -728,7 +733,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             /// </summary>
             /// <param name="info"></param>
             /// <param name="context"></param>
-            public GoodException(SerializationInfo info, StreamingContext context)
+            protected GoodException(SerializationInfo info, StreamingContext context)
             {
                 Mode = (ErrorMode)info.GetInt32("mode");
             }
@@ -745,10 +750,10 @@ namespace Apache.Ignite.Core.Tests.Compute
         /// <summary>
         /// Not marshalable exception.
         /// </summary>
-        public class BadException : Exception
+        private class BadException : Exception
         {
             /** */
-            public ErrorMode Mode;
+            public readonly ErrorMode Mode;
 
             /// <summary>
             /// 

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/SerializableClosureTaskTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/SerializableClosureTaskTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/SerializableClosureTaskTest.cs
index 9f1ae68..ecb4aa5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/SerializableClosureTaskTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Compute/SerializableClosureTaskTest.cs
@@ -54,11 +54,11 @@ namespace Apache.Ignite.Core.Tests.Compute
         /** <inheritDoc /> */
         protected override void CheckResult(object res)
         {
-            Assert.IsTrue(res != null);
+            Assert.IsNotNull(res);
 
-            SerializableResult res0 = res as SerializableResult;
+            var res0 = res as SerializableResult;
 
-            Assert.IsTrue(res0 != null);
+            Assert.IsNotNull(res0);
             Assert.AreEqual(1, res0.Res);
         }
 
@@ -72,9 +72,10 @@ namespace Apache.Ignite.Core.Tests.Compute
             if (aggregate != null)
                 err = aggregate.InnerException;
 
-            SerializableException err0 = err as SerializableException;
+            Assert.IsNotNull(err);
+            SerializableException err0 = err.InnerException as SerializableException;
 
-            Assert.IsTrue(err0 != null);
+            Assert.IsNotNull(err0);
             Assert.AreEqual(ErrMsg, err0.Msg);
         }
 
@@ -85,12 +86,12 @@ namespace Apache.Ignite.Core.Tests.Compute
         private class SerializableOutFunc : IComputeFunc<object>
         {
             /** Error. */
-            private bool _err;
+            private readonly bool _err;
 
             /// <summary>
             ///
             /// </summary>
-            public SerializableOutFunc()
+            private SerializableOutFunc()
             {
                 // No-op.
             }
@@ -109,6 +110,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             {
                 if (_err)
                     throw new SerializableException(ErrMsg);
+
                 return new SerializableResult(1);
             }
         }
@@ -120,12 +122,12 @@ namespace Apache.Ignite.Core.Tests.Compute
         private class SerializableFunc : IComputeFunc<object, object>
         {
             /** Error. */
-            private bool _err;
+            private readonly bool _err;
 
             /// <summary>
             ///
             /// </summary>
-            public SerializableFunc()
+            private SerializableFunc()
             {
                 // No-op.
             }
@@ -157,12 +159,12 @@ namespace Apache.Ignite.Core.Tests.Compute
         private class SerializableException : Exception
         {
             /** */
-            public string Msg;
+            public readonly string Msg;
 
             /// <summary>
             ///
             /// </summary>
-            public SerializableException()
+            private SerializableException()
             {
                 // No-op.
             }
@@ -180,7 +182,7 @@ namespace Apache.Ignite.Core.Tests.Compute
             /// </summary>
             /// <param name="info"></param>
             /// <param name="context"></param>
-            public SerializableException(SerializationInfo info, StreamingContext context) : base(info, context)
+            protected SerializableException(SerializationInfo info, StreamingContext context) : base(info, context)
             {
                 Msg = info.GetString("msg");
             }
@@ -200,12 +202,12 @@ namespace Apache.Ignite.Core.Tests.Compute
         [Serializable]
         private class SerializableResult
         {
-            public int Res;
+            public readonly int Res;
 
             /// <summary>
             ///
             /// </summary>
-            public SerializableResult()
+            private SerializableResult()
             {
                 // No-op.
             }

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
index 567ca2f..7d4c945 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Log/CustomLoggerTest.cs
@@ -130,7 +130,8 @@ namespace Apache.Ignite.Core.Tests.Log
             {
                 var compute = ignite.GetCluster().ForRemotes().GetCompute();
 
-                Assert.Throws<ArithmeticException>(() => compute.Call(new FailFunc()));
+                var ex = Assert.Throws<IgniteException>(() => compute.Call(new FailFunc()));
+                Assert.IsInstanceOf<ArithmeticException>(ex.InnerException);
 
                 // Log updates may not arrive immediately
                 TestUtils.WaitForCondition(() => TestLogger.Entries.Any(x => x.Exception != null), 3000);

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core/Compute/ComputeTaskAdapter.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Compute/ComputeTaskAdapter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Compute/ComputeTaskAdapter.cs
index 79f32a6..a344b51 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Compute/ComputeTaskAdapter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Compute/ComputeTaskAdapter.cs
@@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Compute
     using System.Diagnostics.CodeAnalysis;
     using Apache.Ignite.Core.Cluster;
     using Apache.Ignite.Core.Common;
+    using Apache.Ignite.Core.Impl.Compute;
 
     /// <summary>
     /// Convenience adapter for <see cref="IComputeTask{TArg,TJobRes,TTaskRes}"/> interface
@@ -51,8 +52,7 @@ namespace Apache.Ignite.Core.Compute
 
             if (err != null)
             {
-                if (err is ComputeExecutionRejectedException || err is ClusterTopologyException ||
-                    err is ComputeJobFailoverException)
+                if (Compute.IsFailoverException(err)) 
                     return ComputeJobResultPolicy.Failover;
                 
                 throw new IgniteException("Remote job threw user exception (override or implement " +

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Closure/ComputeAbstractClosureTask.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Closure/ComputeAbstractClosureTask.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Closure/ComputeAbstractClosureTask.cs
index c967c7b..6d6e6a2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Closure/ComputeAbstractClosureTask.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Closure/ComputeAbstractClosureTask.cs
@@ -68,8 +68,7 @@ namespace Apache.Ignite.Core.Impl.Compute.Closure
 
             if (err != null)
             {
-                if (err is ComputeExecutionRejectedException || err is ClusterTopologyException || 
-                    err is ComputeJobFailoverException)
+                if (Compute.IsFailoverException(err))
                     return ComputeJobResultPolicy.Failover;
                 
                 throw err;

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Compute.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Compute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Compute.cs
index efe5905..b54d6a9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Compute.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/Compute.cs
@@ -461,5 +461,22 @@ namespace Apache.Ignite.Core.Impl.Compute
 
             return null;
         }
+
+        /// <summary>
+        /// Determines whether specified exception should result in a job failover.
+        /// </summary>
+        internal static bool IsFailoverException(Exception err)
+        {
+            while (err != null)
+            {
+                if (err is ComputeExecutionRejectedException || err is ClusterTopologyException ||
+                    err is ComputeJobFailoverException)
+                    return true;
+
+                err = err.InnerException;
+            }
+
+            return false;
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
index 6389730..314814d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeJobHolder.cs
@@ -83,7 +83,8 @@ namespace Apache.Ignite.Core.Impl.Compute
 
             _jobRes = new ComputeJobResultImpl(
                 success ? res : null, 
-                success ? null : res as Exception, 
+                success ? null : new IgniteException("Compute job has failed on local node, " +
+                                                     "examine InnerException for details.", (Exception) res), 
                 _job, 
                 _ignite.GetLocalNode().Id, 
                 cancel

http://git-wip-us.apache.org/repos/asf/ignite/blob/97c2a3ce/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeTaskHolder.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeTaskHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeTaskHolder.cs
index a6d7cb4..489fe44 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeTaskHolder.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Compute/ComputeTaskHolder.cs
@@ -327,7 +327,13 @@ namespace Apache.Ignite.Core.Impl.Compute
                 var data = BinaryUtils.ReadInvocationResult(reader, out err);
 
                 // 2. Process the result.
-                return (int) JobResult0(new ComputeJobResultImpl(data, (Exception) err, job.Job, nodeId.Value, cancelled));
+                var exception = (Exception) err;
+                exception = exception == null
+                    ? null
+                    : new IgniteException("Compute job has failed on remote node, " +
+                                          "examine InnerException for details.", exception);
+
+                return (int) JobResult0(new ComputeJobResultImpl(data, exception, job.Job, nodeId.Value, cancelled));
             }
             catch (Exception e)
             {