[REEF-1286] Forward .NET Exceptions from the Evaluator to the Driver
This addressed the issue by
* Adding Serializing of Evaluator Exceptions.
* Modifying the FailedEvaluator test for both serializable and non-serializable Exceptions.
JIRA:
[REEF-1286](https://issues.apache.org/jira/browse/REEF-1286)
This close #988
diff --git a/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h b/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h
index d00ae59..e3fef8a 100644
--- a/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h
+++ b/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h
@@ -158,12 +158,11 @@
virtual void OnError(String^ message);
virtual IEvaluatorRequestorClr2Java^ GetEvaluatorRequestor();
virtual String^ GetId();
- virtual EvaluatorException^ GetException();
virtual array<IFailedContextClr2Java^>^ GetFailedContextsClr2Java();
virtual IFailedTaskClr2Java^ GetFailedTaskClr2Java();
- private:
- String^ GetCause();
- String^ GetStackTrace();
+ virtual array<byte>^ GetErrorBytes();
+ virtual String^ GetJavaCause();
+ virtual String^ GetJavaStackTrace();
};
public ref class HttpServerClr2Java : public IHttpServerBridgeClr2Java {
diff --git a/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp b/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp
index 9f0c8f5..f033c24 100644
--- a/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp
+++ b/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp
@@ -76,12 +76,6 @@
return ManagedStringFromJavaString(env, _jstringId);
}
- EvaluatorException^ FailedEvaluatorClr2Java::GetException() {
- String^ cause = this->GetCause();
- String^ stackTrace = this->GetStackTrace();
- return gcnew EvaluatorException(this->GetId(), cause, stackTrace);
- }
-
array<IFailedContextClr2Java^>^ FailedEvaluatorClr2Java::GetFailedContextsClr2Java() {
JNIEnv *env = RetrieveEnv(_jvm);
jclass jclassFailedEvaluator = env->GetObjectClass(_jobjectFailedEvaluator);
@@ -122,7 +116,20 @@
HandleClr2JavaError(env, message, _jobjectFailedEvaluator);
}
- String^ FailedEvaluatorClr2Java::GetCause() {
+ array<byte>^ FailedEvaluatorClr2Java::GetErrorBytes() {
+ JNIEnv *env = RetrieveEnv(_jvm);
+ jclass jclassFailedEvaluator = env->GetObjectClass(_jobjectFailedEvaluator);
+ jmethodID jmidGetError = env->GetMethodID(jclassFailedEvaluator, "getErrorBytes", "()[B");
+ jobject methodCallReturn = env->CallObjectMethod(_jobjectFailedEvaluator, jmidGetError);
+ if (methodCallReturn == NULL) {
+ return nullptr;
+ }
+
+ jbyteArray error = reinterpret_cast<jbyteArray>(methodCallReturn);
+ return ManagedByteArrayFromJavaByteArray(env, error);
+ }
+
+ String^ FailedEvaluatorClr2Java::GetJavaCause() {
JNIEnv *env = RetrieveEnv(_jvm);
jclass jclassFailedEvaluator = env->GetObjectClass(_jobjectFailedEvaluator);
jmethodID jmidGetCause = env->GetMethodID(jclassFailedEvaluator, "getCause", "()Ljava/lang/String;");
@@ -135,7 +142,7 @@
return ManagedStringFromJavaString(env, cause);
}
- String^ FailedEvaluatorClr2Java::GetStackTrace() {
+ String^ FailedEvaluatorClr2Java::GetJavaStackTrace() {
JNIEnv *env = RetrieveEnv(_jvm);
jclass jclassFailedEvaluator = env->GetObjectClass(_jobjectFailedEvaluator);
jmethodID jmidGetStackTrace = env->GetMethodID(jclassFailedEvaluator, "getStackTrace", "()Ljava/lang/String;");
diff --git a/lang/cs/Org.Apache.REEF.Common/Exceptions/NonSerializableEvaluatorException.cs b/lang/cs/Org.Apache.REEF.Common/Exceptions/NonSerializableEvaluatorException.cs
new file mode 100644
index 0000000..8ce0913
--- /dev/null
+++ b/lang/cs/Org.Apache.REEF.Common/Exceptions/NonSerializableEvaluatorException.cs
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.Runtime.Serialization;
+
+namespace Org.Apache.REEF.Common.Exceptions
+{
+ /// <summary>
+ /// Encapsulates <see cref="Exception#ToString"/> for an Exception from a
+ /// REEF Evaluator that was not Serializable to the Job Driver.
+ /// </summary>
+ [Serializable]
+ public sealed class NonSerializableEvaluatorException : Exception
+ {
+ public NonSerializableEvaluatorException(string message, SerializationException serializationException)
+ : base(message, serializationException)
+ {
+ }
+
+ public NonSerializableEvaluatorException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj b/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj
index 313d06a..b48e0e2 100644
--- a/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj
+++ b/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj
@@ -107,6 +107,7 @@
<Compile Include="Events\IContextStart.cs" />
<Compile Include="Events\IContextStop.cs" />
<Compile Include="Exceptions\JobException.cs" />
+ <Compile Include="Exceptions\NonSerializableEvaluatorException.cs" />
<Compile Include="Exceptions\NonSerializableTaskException.cs" />
<Compile Include="Files\PathUtilities.cs" />
<Compile Include="IContextAndTaskSubmittable.cs" />
diff --git a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs
index 4c86218..1c92192 100644
--- a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs
@@ -17,10 +17,13 @@
using System;
using System.Globalization;
+using System.IO;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using Org.Apache.REEF.Common.Exceptions;
using Org.Apache.REEF.Common.Protobuf.ReefProtocol;
using Org.Apache.REEF.Common.Runtime.Evaluator.Context;
using Org.Apache.REEF.Tang.Annotations;
-using Org.Apache.REEF.Utilities;
using Org.Apache.REEF.Utilities.Diagnostics;
using Org.Apache.REEF.Utilities.Logging;
using Org.Apache.REEF.Wake.Time;
@@ -242,17 +245,31 @@
Logger.Log(Level.Error, "Evaluator {0} failed with exception {1}.", _evaluatorId, e);
_state = State.FAILED;
- var errorMessage = string.Format(
- CultureInfo.InvariantCulture,
- "failed with error [{0}] with message [{1}] and stack trace [{2}]",
- e,
- e.Message,
- e.StackTrace);
+ byte[] errorBytes = null;
+
+ try
+ {
+ using (var memStream = new MemoryStream())
+ {
+ var formatter = new BinaryFormatter();
+ formatter.Serialize(memStream, e);
+ errorBytes = memStream.ToArray();
+ }
+ }
+ catch (SerializationException se)
+ {
+ using (var memStream = new MemoryStream())
+ {
+ var formatter = new BinaryFormatter();
+ formatter.Serialize(memStream, new NonSerializableEvaluatorException(e.ToString(), se));
+ errorBytes = memStream.ToArray();
+ }
+ }
var evaluatorStatusProto = new EvaluatorStatusProto()
{
evaluator_id = _evaluatorId,
- error = ByteUtilities.StringToByteArrays(errorMessage),
+ error = errorBytes,
state = _state
};
diff --git a/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs b/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs
index 19b51b8..3dcd2ae 100644
--- a/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs
+++ b/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs
@@ -15,7 +15,6 @@
// specific language governing permissions and limitations
// under the License.
-using Org.Apache.REEF.Driver.Evaluator;
using Org.Apache.REEF.Utilities.Attributes;
namespace Org.Apache.REEF.Driver.Bridge.Clr2java
@@ -23,14 +22,39 @@
[Private, Interop("FailedEvaluatorClr2Java.cpp", "Clr2JavaImpl.h")]
public interface IFailedEvaluatorClr2Java
{
+ /// <summary>
+ /// Gets the Evaluator requestor.
+ /// </summary>
IEvaluatorRequestorClr2Java GetEvaluatorRequestor();
+ /// <summary>
+ /// Gets the ID of the failed Evaluator.
+ /// </summary>
string GetId();
+ /// <summary>
+ /// Gets the failed Contexts on the Evaluator.
+ /// </summary>
IFailedContextClr2Java[] GetFailedContextsClr2Java();
+ /// <summary>
+ /// Gets the failed Task on the Evaluator.
+ /// </summary>
IFailedTaskClr2Java GetFailedTaskClr2Java();
- EvaluatorException GetException();
+ /// <summary>
+ /// Gets the Serialized Exception.
+ /// </summary>
+ byte[] GetErrorBytes();
+
+ /// <summary>
+ /// Gets the Java Exception message.
+ /// </summary>
+ string GetJavaCause();
+
+ /// <summary>
+ /// Gets the Java stack trace.
+ /// </summary>
+ string GetJavaStackTrace();
}
}
diff --git a/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs b/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs
index bf126c0..337b793 100644
--- a/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs
+++ b/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs
@@ -15,9 +15,12 @@
// specific language governing permissions and limitations
// under the License.
+using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
using Org.Apache.REEF.Driver.Bridge.Clr2java;
using Org.Apache.REEF.Driver.Context;
using Org.Apache.REEF.Driver.Evaluator;
@@ -31,6 +34,7 @@
{
private readonly string _id;
private readonly IList<IFailedContext> _failedContexts;
+ private readonly EvaluatorException _evaluatorException;
public FailedEvaluator(IFailedEvaluatorClr2Java clr2Java)
{
@@ -39,6 +43,24 @@
_failedContexts = new List<IFailedContext>(
FailedEvaluatorClr2Java.GetFailedContextsClr2Java().Select(clr2JavaFailedContext =>
new FailedContext(clr2JavaFailedContext)));
+
+ var errorBytes = FailedEvaluatorClr2Java.GetErrorBytes();
+ if (errorBytes != null)
+ {
+ // When the Exception originates from the C# side.
+ var formatter = new BinaryFormatter();
+ using (var memStream = new MemoryStream(errorBytes))
+ {
+ var inner = (Exception)formatter.Deserialize(memStream);
+ _evaluatorException = new EvaluatorException(_id, inner.Message, inner);
+ }
+ }
+ else
+ {
+ // When the Exception originates from Java.
+ _evaluatorException = new EvaluatorException(
+ _id, FailedEvaluatorClr2Java.GetJavaCause(), FailedEvaluatorClr2Java.GetJavaStackTrace());
+ }
}
[DataMember]
@@ -51,7 +73,7 @@
public EvaluatorException EvaluatorException
{
- get { return FailedEvaluatorClr2Java.GetException(); }
+ get { return _evaluatorException; }
}
public IList<IFailedContext> FailedContexts
diff --git a/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs b/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs
index c21a113..5d67f38 100644
--- a/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs
+++ b/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs
@@ -26,12 +26,20 @@
private readonly string _evaluatorId;
private readonly Optional<string> _javaStackTrace;
- [Private]
- public EvaluatorException(string evaluatorId, string message, string javaStackTrace)
+ internal EvaluatorException(string evaluatorId, string message, string javaStackTrace)
: base(message)
{
_evaluatorId = evaluatorId;
- _javaStackTrace = Optional<string>.OfNullable(javaStackTrace);
+ _javaStackTrace = string.IsNullOrWhiteSpace(javaStackTrace)
+ ? Optional<string>.Empty()
+ : Optional<string>.Of(javaStackTrace);
+ }
+
+ internal EvaluatorException(string evaluatorId, string message, Exception inner)
+ : base(message, inner)
+ {
+ _evaluatorId = evaluatorId;
+ _javaStackTrace = Optional<string>.Empty();
}
public string EvaluatorId
diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestNonSerializableException.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestNonSerializableException.cs
new file mode 100644
index 0000000..3fcea6c
--- /dev/null
+++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestNonSerializableException.cs
@@ -0,0 +1,29 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+
+namespace Org.Apache.REEF.Tests.Functional.Bridge.Exceptions
+{
+ internal sealed class TestNonSerializableException : Exception
+ {
+ public TestNonSerializableException(string message)
+ : base(message)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestSerializableException.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestSerializableException.cs
new file mode 100644
index 0000000..ee9840e
--- /dev/null
+++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestSerializableException.cs
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.Runtime.Serialization;
+
+namespace Org.Apache.REEF.Tests.Functional.Bridge.Exceptions
+{
+ [Serializable]
+ internal sealed class TestSerializableException : Exception
+ {
+ public TestSerializableException(string message)
+ : base(message)
+ {
+ }
+
+ public TestSerializableException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Parameters/ShouldThrowSerializableException.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Parameters/ShouldThrowSerializableException.cs
new file mode 100644
index 0000000..544026d
--- /dev/null
+++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Parameters/ShouldThrowSerializableException.cs
@@ -0,0 +1,29 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using Org.Apache.REEF.Tang.Annotations;
+
+namespace Org.Apache.REEF.Tests.Functional.Bridge.Parameters
+{
+ [NamedParameter(documentation: "Used to indicate whether FailTask should throw a Serializable or non-Serializable Exception.")]
+ internal sealed class ShouldThrowSerializableException : Name<bool>
+ {
+ private ShouldThrowSerializableException()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs
index dfcb9f6..251dc61 100644
--- a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs
+++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs
@@ -28,6 +28,8 @@
using Org.Apache.REEF.Tang.Implementations.Tang;
using Org.Apache.REEF.Tang.Interface;
using Org.Apache.REEF.Tang.Util;
+using Org.Apache.REEF.Tests.Functional.Bridge.Exceptions;
+using Org.Apache.REEF.Tests.Functional.Bridge.Parameters;
using Org.Apache.REEF.Utilities.Logging;
using Xunit;
@@ -204,35 +206,5 @@
throw new TestNonSerializableException(ExpectedExceptionMessage);
}
}
-
- [NamedParameter(documentation: "Used to indicate whether FailTask should throw a Serializable or non-Serializable Exception.")]
- private sealed class ShouldThrowSerializableException : Name<bool>
- {
- private ShouldThrowSerializableException()
- {
- }
- }
-
- [Serializable]
- private sealed class TestSerializableException : Exception
- {
- public TestSerializableException(string message)
- : base(message)
- {
- }
-
- public TestSerializableException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
- }
-
- private sealed class TestNonSerializableException : Exception
- {
- public TestNonSerializableException(string message)
- : base(message)
- {
- }
- }
}
}
diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs
index ec8fc07..fda2c0c 100644
--- a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs
+++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs
@@ -17,13 +17,18 @@
using System;
using System.Threading;
+using Org.Apache.REEF.Common.Exceptions;
using Org.Apache.REEF.Common.Tasks;
using Org.Apache.REEF.Driver;
using Org.Apache.REEF.Driver.Evaluator;
using Org.Apache.REEF.Driver.Task;
using Org.Apache.REEF.Tang.Annotations;
+using Org.Apache.REEF.Tang.Implementations.Configuration;
+using Org.Apache.REEF.Tang.Implementations.Tang;
using Org.Apache.REEF.Tang.Interface;
using Org.Apache.REEF.Tang.Util;
+using Org.Apache.REEF.Tests.Functional.Bridge.Exceptions;
+using Org.Apache.REEF.Tests.Functional.Bridge.Parameters;
using Org.Apache.REEF.Utilities.Logging;
using Xunit;
@@ -34,21 +39,21 @@
{
private const string ExpectedEvaluatorFailureMessage = "Unhandled Exception.";
private const string ExpectedTaskId = "TaskID";
- private const string SuccessMessage = "Evaluator successfully received unhandled Exception.";
+ private const string SerializableSuccessMessage = "Evaluator successfully received serializable unhandled Exception.";
+ private const string NonSerializableSuccessMessage = "Evaluator successfully received nonserializable unhandled Exception.";
/// <summary>
/// This test validates that an unhandled Task Exception crashes the Evaluator and the Evaluator
/// does an attempt to send a final message to the Driver.
- /// TODO[JIRA REEF-1286]: Currently, this only validates the first portion, but does not yet validate the final message.
- /// TODO[JIRA REEF-1286]: The verification of the final message can be done when the Exceptions are serializable.
/// </summary>
[Fact]
public void TestUnhandledTaskExceptionCrashesEvaluator()
{
var testFolder = DefaultRuntimeFolder + Guid.NewGuid().ToString("N").Substring(0, 4);
TestRun(GetDriverConfiguration(), typeof(TestUnhandledTaskException), 1, "testUnhandledTaskException", "local", testFolder);
- ValidateSuccessForLocalRuntime(0, numberOfEvaluatorsToFail: 1, testFolder: testFolder);
- ValidateMessageSuccessfullyLoggedForDriver(SuccessMessage, testFolder, 1);
+ ValidateSuccessForLocalRuntime(0, numberOfEvaluatorsToFail: 2, testFolder: testFolder);
+ ValidateMessageSuccessfullyLoggedForDriver(SerializableSuccessMessage, testFolder, 1);
+ ValidateMessageSuccessfullyLoggedForDriver(NonSerializableSuccessMessage, testFolder, 1);
}
private static IConfiguration GetDriverConfiguration()
@@ -68,16 +73,27 @@
/// </summary>
private sealed class UnhandledExceptionTestTask : ITask
{
+ private readonly bool _shouldThrowSerializableException;
+
[Inject]
- private UnhandledExceptionTestTask()
+ private UnhandledExceptionTestTask(
+ [Parameter(typeof(ShouldThrowSerializableException))] bool shouldThrowSerializableException)
{
+ _shouldThrowSerializableException = shouldThrowSerializableException;
}
public byte[] Call(byte[] memento)
{
var thread = new Thread(() =>
{
- throw new Exception(ExpectedEvaluatorFailureMessage);
+ if (_shouldThrowSerializableException)
+ {
+ throw new TestSerializableException(ExpectedEvaluatorFailureMessage);
+ }
+ else
+ {
+ throw new TestNonSerializableException(ExpectedEvaluatorFailureMessage);
+ }
});
thread.Start();
@@ -105,6 +121,7 @@
private static readonly Logger Logger = Logger.GetLogger(typeof(UnhandledExceptionTestDriver));
private readonly IEvaluatorRequestor _evaluatorRequestor;
+ private bool _shouldReceiveSerializableException = true;
[Inject]
private UnhandledExceptionTestDriver(IEvaluatorRequestor evaluatorRequestor)
@@ -128,7 +145,12 @@
.Set(TaskConfiguration.Task, GenericType<UnhandledExceptionTestTask>.Class)
.Build();
- value.SubmitTask(taskConf);
+ var shouldThrowSerializableConfig = TangFactory.GetTang().NewConfigurationBuilder()
+ .BindNamedParameter<ShouldThrowSerializableException, bool>(
+ GenericType<ShouldThrowSerializableException>.Class, _shouldReceiveSerializableException.ToString())
+ .Build();
+
+ value.SubmitTask(Configurations.Merge(taskConf, shouldThrowSerializableConfig));
}
public void OnNext(ICompletedTask value)
@@ -150,7 +172,7 @@
if (!value.EvaluatorException.Message.Contains(ExpectedEvaluatorFailureMessage))
{
- // TODO[JIRA REEF-1286]: Verify the Exception message and the type of Exception.
+ throw new Exception("Evaluator expected to contain the message " + ExpectedEvaluatorFailureMessage);
}
if (!value.FailedTask.IsPresent())
@@ -163,7 +185,43 @@
throw new Exception("Failed Task does not have the right Task ID.");
}
- Logger.Log(Level.Info, SuccessMessage);
+ if (_shouldReceiveSerializableException)
+ {
+ var serializableEx = value.EvaluatorException.InnerException as TestSerializableException;
+ if (serializableEx == null)
+ {
+ throw new Exception("Evaluator InnerException expected to be of type " + typeof(TestSerializableException).Name);
+ }
+
+ if (!serializableEx.Message.Equals(ExpectedEvaluatorFailureMessage))
+ {
+ throw new Exception("Evaluator InnerException.Message expected to be " + ExpectedEvaluatorFailureMessage);
+ }
+
+ _shouldReceiveSerializableException = false;
+ Logger.Log(Level.Info, SerializableSuccessMessage);
+
+ _evaluatorRequestor.Submit(
+ _evaluatorRequestor.NewBuilder()
+ .SetCores(1)
+ .SetNumber(1)
+ .Build());
+ }
+ else
+ {
+ var nonSerializableEx = value.EvaluatorException.InnerException as NonSerializableEvaluatorException;
+ if (nonSerializableEx == null)
+ {
+ throw new Exception("Evaluator Exception expected to be of type " + typeof(NonSerializableEvaluatorException));
+ }
+
+ if (!nonSerializableEx.Message.Contains(ExpectedEvaluatorFailureMessage))
+ {
+ throw new Exception("Evaluator InnerException.Message expected to contain the message " + ExpectedEvaluatorFailureMessage);
+ }
+
+ Logger.Log(Level.Info, NonSerializableSuccessMessage);
+ }
}
public void OnError(Exception error)
diff --git a/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj b/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj
index bf58810..293f8d4 100644
--- a/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj
+++ b/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj
@@ -74,11 +74,14 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Functional\Bridge\HelloSimpleEventHandlers.cs" />
+ <Compile Include="Functional\Bridge\Parameters\ShouldThrowSerializableException.cs" />
<Compile Include="Functional\Bridge\TestBridgeClient.cs" />
<Compile Include="Functional\Bridge\TestCloseTask.cs" />
<Compile Include="Functional\Bridge\TestContextStack.cs" />
<Compile Include="Functional\Bridge\TestFailedEvaluatorEventHandler.cs" />
<Compile Include="Functional\Bridge\TestFailedTaskEventHandler.cs" />
+ <Compile Include="Functional\Bridge\Exceptions\TestNonSerializableException.cs" />
+ <Compile Include="Functional\Bridge\Exceptions\TestSerializableException.cs" />
<Compile Include="Functional\Bridge\TestSimpleContext.cs" />
<Compile Include="Functional\Bridge\TestSimpleEventHandlers.cs" />
<Compile Include="Functional\Bridge\TestSuspendTask.cs" />
@@ -181,6 +184,7 @@
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Import Project="$(PackagesDir)\StyleCop.MSBuild.$(StyleCopVersion)\build\StyleCop.MSBuild.Targets" Condition="Exists('$(PackagesDir)\StyleCop.MSBuild.$(StyleCopVersion)\build\StyleCop.MSBuild.Targets')" />
diff --git a/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java b/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java
index 89be5f3..8acabce 100644
--- a/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java
+++ b/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java
@@ -23,6 +23,7 @@
import org.apache.reef.annotations.audience.Private;
import org.apache.reef.driver.evaluator.EvaluatorRequestor;
import org.apache.reef.driver.evaluator.FailedEvaluator;
+import org.apache.reef.exception.NonSerializableException;
import org.apache.reef.io.naming.Identifiable;
import org.apache.reef.util.logging.LoggingScopeFactory;
@@ -55,14 +56,36 @@
this.activeContextBridgeFactory = activeContextBridgeFactory;
}
+ /**
+ * @return the Evaluator number.
+ */
public int getNewlyRequestedEvaluatorNumber() {
return evaluatorRequestorBridge.getEvaluatorNumber();
}
+ /**
+ * @return the Evaluator requestor.
+ */
public EvaluatorRequestorBridge getEvaluatorRequestorBridge() {
return evaluatorRequestorBridge;
}
+ /**
+ * @return the non-serializable error in bytes, may translate into a serialized C# Exception.
+ */
+ public byte[] getErrorBytes() {
+ if (jfailedEvaluator.getEvaluatorException() != null &&
+ jfailedEvaluator.getEvaluatorException().getCause() instanceof NonSerializableException) {
+ return ((NonSerializableException)jfailedEvaluator.getEvaluatorException().getCause()).getError();
+ }
+
+ // If not an instance of NonSerializableException, that means that the Exception is from Java.
+ return null;
+ }
+
+ /**
+ * @return the localized message of the Evaluator Exception.
+ */
public String getCause() {
if (jfailedEvaluator.getEvaluatorException() != null) {
return jfailedEvaluator.getEvaluatorException().getLocalizedMessage();
@@ -71,6 +94,9 @@
return null;
}
+ /**
+ * @return the stack trace of the Evaluator Exception.
+ */
public String getStackTrace() {
if (jfailedEvaluator.getEvaluatorException() != null) {
return ExceptionUtils.getStackTrace(jfailedEvaluator.getEvaluatorException());
@@ -79,6 +105,9 @@
return null;
}
+ /**
+ * @return the list of failed Contexts associated with the Evaluator.
+ */
public FailedContextBridge[] getFailedContexts() {
if (jfailedEvaluator.getFailedContextList() == null) {
return new FailedContextBridge[0];
@@ -95,6 +124,9 @@
return failedContextBridges;
}
+ /**
+ * @return the failed task running on the Evaluator, if any.
+ */
public FailedTaskBridge getFailedTask() {
if (!jfailedEvaluator.getFailedTask().isPresent()) {
return null;
diff --git a/lang/java/reef-common/src/main/java/org/apache/reef/exception/NonSerializableException.java b/lang/java/reef-common/src/main/java/org/apache/reef/exception/NonSerializableException.java
new file mode 100644
index 0000000..3286c98
--- /dev/null
+++ b/lang/java/reef-common/src/main/java/org/apache/reef/exception/NonSerializableException.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.reef.exception;
+
+import org.apache.reef.annotations.audience.DriverSide;
+
+/**
+ * An {@link Exception} that indicates that an Exception from the Evaluator
+ * was not able to be serialized.
+ */
+@DriverSide
+public final class NonSerializableException extends Exception {
+ private final byte[] error;
+
+ public NonSerializableException(final String message, final byte[] error) {
+ super(message);
+ this.error = error;
+ }
+
+ /**
+ * @return the Exception representation in a byte array.
+ */
+ public byte[] getError() {
+ return error;
+ }
+}
diff --git a/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java b/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java
index e364ff1..f483868 100644
--- a/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java
+++ b/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java
@@ -24,6 +24,7 @@
import org.apache.reef.driver.parameters.EvaluatorConfigurationProviders;
import org.apache.reef.driver.restart.DriverRestartManager;
import org.apache.reef.driver.restart.EvaluatorRestartState;
+import org.apache.reef.exception.NonSerializableException;
import org.apache.reef.runtime.common.driver.evaluator.pojos.ContextStatusPOJO;
import org.apache.reef.runtime.common.driver.evaluator.pojos.EvaluatorStatusPOJO;
import org.apache.reef.runtime.common.driver.evaluator.pojos.State;
@@ -468,7 +469,7 @@
evaluatorException = new EvaluatorException(getId(), exception.get());
} else {
evaluatorException = new EvaluatorException(getId(),
- new Exception("Exception sent, but can't be deserialized"));
+ new NonSerializableException("Exception sent, but can't be deserialized", evaluatorStatus.getError()));
}
} else {
evaluatorException = new EvaluatorException(getId(), new Exception("No exception sent"));