From 655df0d9c0714a408fb85cd822cbfff48375f49b Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Wed, 8 Jan 2020 04:52:01 -0500 Subject: [PATCH] improve exception handling in threads --- .../util/daemon/ExceptionHandler.java | 25 +++++++++++++++ .../cobbzilla/util/daemon/ZillaRuntime.java | 23 ++------------ .../org/cobbzilla/util/main/BaseMain.java | 31 ++++++++++++------- 3 files changed, 47 insertions(+), 32 deletions(-) create mode 100644 src/main/java/org/cobbzilla/util/daemon/ExceptionHandler.java diff --git a/src/main/java/org/cobbzilla/util/daemon/ExceptionHandler.java b/src/main/java/org/cobbzilla/util/daemon/ExceptionHandler.java new file mode 100644 index 0000000..90fe188 --- /dev/null +++ b/src/main/java/org/cobbzilla/util/daemon/ExceptionHandler.java @@ -0,0 +1,25 @@ +package org.cobbzilla.util.daemon; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public interface ExceptionHandler { + + void handle(Exception e); + + Logger log = LoggerFactory.getLogger(ExceptionHandler.class); + + ExceptionHandler DEFAULT_EX_RUNNABLE = e -> log.error("Error: " + e); + + static ExceptionHandler exceptionRunnable(Class[] fatalExceptionClasses) { + return e -> { + for (Class c : fatalExceptionClasses) { + if (c.isAssignableFrom(e.getClass())) { + if (e instanceof RuntimeException) throw (RuntimeException) e; + ZillaRuntime.die("fatal exception: "+e); + } + } + DEFAULT_EX_RUNNABLE.handle(e); + }; + } +} diff --git a/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java b/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java index 252a9ea..5d9f7e6 100644 --- a/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java +++ b/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java @@ -31,6 +31,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.stream.LongStream.range; import static org.apache.commons.collections.CollectionUtils.collect; import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace; +import static org.cobbzilla.util.daemon.ExceptionHandler.DEFAULT_EX_RUNNABLE; import static org.cobbzilla.util.io.FileUtil.abs; import static org.cobbzilla.util.io.FileUtil.list; import static org.cobbzilla.util.reflect.ReflectionUtil.instantiate; @@ -66,27 +67,9 @@ public class ZillaRuntime { public static boolean bool(Boolean b) { return b != null && b; } public static boolean bool(Boolean b, boolean val) { return b != null ? b : val; } - public interface ExceptionRunnable { void handle(Exception e); } - - public static final ExceptionRunnable DEFAULT_EX_RUNNABLE = e -> { - log.error("Error: " + e); - }; - - public static ExceptionRunnable exceptionRunnable (Class[] fatalExceptionClasses) { - return e -> { - for (Class c : fatalExceptionClasses) { - if (c.isAssignableFrom(e.getClass())) { - if (e instanceof RuntimeException) throw (RuntimeException) e; - die("fatal exception: "+e); - } - } - DEFAULT_EX_RUNNABLE.handle(e); - }; - } - public static Thread background (Runnable r) { return background(r, DEFAULT_EX_RUNNABLE); } - public static Thread background (Runnable r, ExceptionRunnable ex) { + public static Thread background (Runnable r, ExceptionHandler ex) { final Thread t = new Thread(() -> { try { r.run(); @@ -124,7 +107,7 @@ public class ZillaRuntime { public static T retry (Callable func, int tries, Function backoff, - ExceptionRunnable ex) { + ExceptionHandler ex) { Exception lastEx = null; try { for (int i = 0; i < tries; i++) { diff --git a/src/main/java/org/cobbzilla/util/main/BaseMain.java b/src/main/java/org/cobbzilla/util/main/BaseMain.java index 3a160d8..a354382 100644 --- a/src/main/java/org/cobbzilla/util/main/BaseMain.java +++ b/src/main/java/org/cobbzilla/util/main/BaseMain.java @@ -1,8 +1,10 @@ package org.cobbzilla.util.main; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.cobbzilla.util.daemon.ExceptionHandler; import org.cobbzilla.util.daemon.ZillaRuntime; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; @@ -22,18 +24,6 @@ public abstract class BaseMain { protected abstract void run() throws Exception; - public void runOrDie () { try { run(); } catch (Exception e) { die("runOrDie: "+e, e); } } - - public void runOrDie (ZillaRuntime.ExceptionRunnable errorHandler) { - try { run(); } catch (Exception e) { errorHandler.handle(e); } - } - - public Thread runInBackground () { return background(this::runOrDie); } - - public Thread runInBackground (ZillaRuntime.ExceptionRunnable errorHandler) { - return background(() -> runOrDie(errorHandler)); - } - @Getter private String[] args; public void setArgs(String[] args) throws CmdLineException { this.args = args; @@ -116,4 +106,21 @@ public abstract class BaseMain { System.exit(1); return null; } + + public Thread runInBackground (ExceptionHandler errorHandler) { + return background(new RunWithHandler(this, errorHandler), errorHandler); + } + + @AllArgsConstructor + private static class RunWithHandler implements Runnable { + private final BaseMain runnable; + private final ExceptionHandler errorHandler; + @Override public void run() { + try { + runnable.run(); + } catch (Exception e) { + errorHandler.handle(e); + } + } + } }