1818
1919package org .apache .hadoop .hive .metastore .utils ;
2020
21- import java .util . ArrayList ;
22- import java .util . List ;
21+ import java .lang . reflect . InvocationTargetException ;
22+ import java .lang . reflect . UndeclaredThrowableException ;
2323import java .util .concurrent .Callable ;
24+ import java .util .function .Function ;
25+ import java .util .function .Predicate ;
2426
27+ import org .apache .commons .lang3 .exception .ExceptionUtils ;
2528import org .apache .hadoop .hive .metastore .api .MetaException ;
2629import org .slf4j .Logger ;
2730import org .slf4j .LoggerFactory ;
2831
2932public class RetryingExecutor <T > {
30- private static Logger LOG = LoggerFactory .getLogger (RetryingExecutor .class );
33+ private static final Logger LOG = LoggerFactory .getLogger (RetryingExecutor .class );
3134
3235 private final int maxRetries ;
33- private final long sleepInterval ;
36+ private long sleepInterval = 1000 ;
3437 private final Callable <T > command ;
35- private final List < Class <? extends Exception >> retriableException = new ArrayList <>() ;
38+ private Predicate < Exception > retryPolicy ;
3639 private int currentRetries = 0 ;
3740 private String commandName ;
41+ private Function <Long , Long > sleepIntervalFunc ;
3842
39- public RetryingExecutor (int maxRetries , long sleepInterval , Callable <T > command ) {
43+ public RetryingExecutor (int maxRetries , Callable <T > command ) {
4044 this .maxRetries = maxRetries ;
41- this .sleepInterval = sleepInterval ;
4245 this .command = command ;
46+ // default commandName unless specified
47+ this .commandName = StackWalker .getInstance ()
48+ .walk (frames -> frames
49+ .skip (1 )
50+ .findFirst ()
51+ .map (StackWalker .StackFrame ::getMethodName )).get ();
4352 }
4453
45- public RetryingExecutor <T > onRetry (Class <? extends Exception > ex ) {
46- this .retriableException . add ( ex ) ;
54+ public RetryingExecutor <T > onRetry (Predicate < Exception > retryPolicy ) {
55+ this .retryPolicy = retryPolicy ;
4756 return this ;
4857 }
4958
@@ -52,6 +61,17 @@ public RetryingExecutor<T> commandName(String name) {
5261 return this ;
5362 }
5463
64+ public RetryingExecutor <T > sleepInterval (long sleepInterval ) {
65+ return sleepInterval (sleepInterval , null );
66+ }
67+
68+ public RetryingExecutor <T > sleepInterval (long sleepInterval ,
69+ Function <Long , Long > sleepIntervalFunc ) {
70+ this .sleepInterval = sleepInterval ;
71+ this .sleepIntervalFunc = sleepIntervalFunc ;
72+ return this ;
73+ }
74+
5575 public T run () throws MetaException {
5676 while (true ) {
5777 try {
@@ -68,7 +88,7 @@ public T run() throws MetaException {
6888 }
6989 currentRetries ++;
7090 try {
71- Thread .sleep (sleepInterval );
91+ Thread .sleep (getSleepInterval () );
7292 } catch (InterruptedException e1 ) {
7393 String msg = "Couldn't run the command: " + commandName + " in " + currentRetries +
7494 " retry, because the following error: " ;
@@ -80,11 +100,16 @@ public T run() throws MetaException {
80100 }
81101
82102 private void checkException (Exception e ) throws MetaException {
83- if (!retriableException .isEmpty () &&
84- retriableException .stream ().noneMatch (nex -> nex .isInstance (e ))) {
85- String message = "See a non-retriable exception, avoid to retry the command:" + commandName ;
103+ if (retryPolicy != null && !retryPolicy .test (e )) {
104+ String message = "See a fatal exception, avoid to retry the command:" + commandName ;
86105 LOG .info (message , e );
87- throw new MetaException (message + " :: " + e .getMessage ());
106+ String errorMessage = ExceptionUtils .getMessage (e );
107+ if (e instanceof InvocationTargetException || e instanceof UndeclaredThrowableException ) {
108+ errorMessage = ExceptionUtils .getMessage (e .getCause ());
109+ }
110+ Throwable rootCause = ExceptionUtils .getRootCause (e );
111+ errorMessage += (rootCause == null ? "" : ("\n Root cause: " + rootCause ));
112+ throw new MetaException (message + " :: " + errorMessage );
88113 }
89114 }
90115
@@ -101,6 +126,9 @@ public RetryException(String msg) {
101126 }
102127
103128 public long getSleepInterval () {
129+ if (sleepIntervalFunc != null ) {
130+ this .sleepInterval = sleepIntervalFunc .apply (sleepInterval );
131+ }
104132 return sleepInterval ;
105133 }
106- }
134+ }
0 commit comments