-
Notifications
You must be signed in to change notification settings - Fork 28.9k
[SPARK-24243][CORE] Expose exceptions from InProcessAppHandle #21849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
| package org.apache.spark.launcher; | ||
|
|
||
| import java.io.InputStream; | ||
| import java.util.Optional; | ||
| import java.util.logging.Level; | ||
| import java.util.logging.Logger; | ||
|
|
||
|
|
@@ -29,7 +30,7 @@ class ChildProcAppHandle extends AbstractAppHandle { | |
| private static final Logger LOG = Logger.getLogger(ChildProcAppHandle.class.getName()); | ||
|
|
||
| private volatile Process childProc; | ||
| private OutputRedirector redirector; | ||
| private volatile OutputRedirector redirector; | ||
|
|
||
| ChildProcAppHandle(LauncherServer server) { | ||
| super(server); | ||
|
|
@@ -46,6 +47,25 @@ public synchronized void disconnect() { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Parses the logs of {@code spark-submit} and returns the last exception thrown. | ||
| * | ||
| * <p> | ||
| * Since {@link SparkLauncher} runs {@code spark-submit} in a sub-process, its difficult to | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's also, small nit: keep the text at the same indent level as the p tags (as is done in other classes). |
||
| * accurately retrieve the full {@link Throwable} from the {@code spark-submit} process. | ||
| * This method parses the logs of the sub-process and provides a best-effort attempt at | ||
| * returning the last exception thrown by the {@code spark-submit} process. Only the exception | ||
| * message is parsed, the associated stacktrace is meaningless. | ||
| * </p> | ||
| * | ||
| * @return an {@link Optional} containing a {@link RuntimeException} with the parsed | ||
| * exception, otherwise returns a {@link Optional#EMPTY} | ||
| */ | ||
| @Override | ||
| public Optional<Throwable> getError() { | ||
| return redirector != null ? Optional.ofNullable(redirector.getError()) : Optional.empty(); | ||
| } | ||
|
|
||
| @Override | ||
| public synchronized void kill() { | ||
| if (!isDisposed()) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,7 @@ class OutputRedirector { | |
| private final ChildProcAppHandle callback; | ||
|
|
||
| private volatile boolean active; | ||
| private volatile Throwable error; | ||
|
|
||
| OutputRedirector(InputStream in, String loggerName, ThreadFactory tf) { | ||
| this(in, loggerName, tf, null); | ||
|
|
@@ -61,6 +62,10 @@ private void redirect() { | |
| while ((line = reader.readLine()) != null) { | ||
| if (active) { | ||
| sink.info(line.replaceFirst("\\s*$", "")); | ||
| if (error == null && containsIgnoreCase(line, "Error") || containsIgnoreCase(line, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: group the conditions so people don't have to remember how precedence work. Also it looks better if you keep the whole call to Wouldn't you want to keep the last error, though, instead of the first one? |
||
| "Exception")) { | ||
| error = new RuntimeException(line); | ||
| } | ||
| } | ||
| } | ||
| } catch (IOException e) { | ||
|
|
@@ -85,4 +90,24 @@ boolean isAlive() { | |
| return thread.isAlive(); | ||
| } | ||
|
|
||
| Throwable getError() { | ||
| return error; | ||
| } | ||
|
|
||
| /** | ||
| * Copied from Apache Commons Lang {@code StringUtils#containsIgnoreCase(String, String)} | ||
| */ | ||
| private static boolean containsIgnoreCase(String str, String searchStr) { | ||
| if (str == null || searchStr == null) { | ||
| return false; | ||
| } | ||
| int len = searchStr.length(); | ||
| int max = str.length() - len; | ||
| for (int i = 0; i <= max; i++) { | ||
| if (str.regionMatches(true, i, searchStr, 0, len)) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -106,7 +106,10 @@ object MimaExcludes { | |
| ProblemFilters.exclude[InheritedNewAbstractMethodProblem]("org.apache.spark.ml.param.shared.HasValidationIndicatorCol.validationIndicatorCol"), | ||
|
|
||
| // [SPARK-23042] Use OneHotEncoderModel to encode labels in MultilayerPerceptronClassifier | ||
| ProblemFilters.exclude[MissingClassProblem]("org.apache.spark.ml.classification.LabelConverter") | ||
| ProblemFilters.exclude[MissingClassProblem]("org.apache.spark.ml.classification.LabelConverter"), | ||
|
|
||
| // [SPARK-24243][CORE] Expose exceptions from InProcessAppHandle | ||
| ProblemFilters.exclude[ReversedMissingMethodProblem]("org.apache.spark.launcher.SparkAppHandle.getError") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: add at the top of the list (then you don't have to touch existing entries). |
||
| ) | ||
|
|
||
| // Exclude rules for 2.3.x | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't really necessary since
ErrorInProcessTestAppdoes not create a context; but not a big deal either.