19
19
import java .time .Clock ;
20
20
import java .time .Duration ;
21
21
import java .time .Instant ;
22
+ import java .util .concurrent .Callable ;
22
23
import java .util .concurrent .Executor ;
23
24
import java .util .concurrent .Future ;
24
25
import java .util .concurrent .RejectedExecutionException ;
41
42
import org .springframework .scheduling .Trigger ;
42
43
import org .springframework .scheduling .support .DelegatingErrorHandlingRunnable ;
43
44
import org .springframework .scheduling .support .TaskUtils ;
45
+ import org .springframework .util .Assert ;
44
46
import org .springframework .util .ErrorHandler ;
47
+ import org .springframework .util .concurrent .ListenableFuture ;
45
48
46
49
/**
47
50
* A simple implementation of Spring's {@link TaskScheduler} interface, using
@@ -108,6 +111,9 @@ public class SimpleAsyncTaskScheduler extends SimpleAsyncTaskExecutor implements
108
111
109
112
private final ExecutorLifecycleDelegate lifecycleDelegate = new ExecutorLifecycleDelegate (this .scheduledExecutor );
110
113
114
+ @ Nullable
115
+ private ErrorHandler errorHandler ;
116
+
111
117
private Clock clock = Clock .systemDefaultZone ();
112
118
113
119
private int phase = DEFAULT_PHASE ;
@@ -119,13 +125,22 @@ public class SimpleAsyncTaskScheduler extends SimpleAsyncTaskExecutor implements
119
125
private ApplicationContext applicationContext ;
120
126
121
127
128
+ /**
129
+ * Provide an {@link ErrorHandler} strategy.
130
+ * @since 6.2
131
+ */
132
+ public void setErrorHandler (ErrorHandler errorHandler ) {
133
+ Assert .notNull (errorHandler , "ErrorHandler must not be null" );
134
+ this .errorHandler = errorHandler ;
135
+ }
136
+
122
137
/**
123
138
* Set the clock to use for scheduling purposes.
124
139
* <p>The default clock is the system clock for the default time zone.
125
- * @since 5.3
126
140
* @see Clock#systemDefaultZone()
127
141
*/
128
142
public void setClock (Clock clock ) {
143
+ Assert .notNull (clock , "Clock must not be null" );
129
144
this .clock = clock ;
130
145
}
131
146
@@ -194,15 +209,19 @@ protected void doExecute(Runnable task) {
194
209
}
195
210
196
211
private Runnable taskOnSchedulerThread (Runnable task ) {
197
- return new DelegatingErrorHandlingRunnable (task , TaskUtils .getDefaultErrorHandler (true ));
212
+ return new DelegatingErrorHandlingRunnable (task ,
213
+ (this .errorHandler != null ? this .errorHandler : TaskUtils .getDefaultErrorHandler (true )));
198
214
}
199
215
200
216
private Runnable scheduledTask (Runnable task ) {
201
217
return () -> execute (new DelegatingErrorHandlingRunnable (task , this ::shutdownAwareErrorHandler ));
202
218
}
203
219
204
220
private void shutdownAwareErrorHandler (Throwable ex ) {
205
- if (this .scheduledExecutor .isTerminated ()) {
221
+ if (this .errorHandler != null ) {
222
+ this .errorHandler .handleError (ex );
223
+ }
224
+ else if (this .scheduledExecutor .isTerminated ()) {
206
225
LogFactory .getLog (getClass ()).debug ("Ignoring scheduled task exception after shutdown" , ex );
207
226
}
208
227
else {
@@ -211,12 +230,40 @@ private void shutdownAwareErrorHandler(Throwable ex) {
211
230
}
212
231
213
232
233
+ @ Override
234
+ public void execute (Runnable task ) {
235
+ super .execute (TaskUtils .decorateTaskWithErrorHandler (task , this .errorHandler , false ));
236
+ }
237
+
238
+ @ Override
239
+ public Future <?> submit (Runnable task ) {
240
+ return super .submit (TaskUtils .decorateTaskWithErrorHandler (task , this .errorHandler , false ));
241
+ }
242
+
243
+ @ Override
244
+ public <T > Future <T > submit (Callable <T > task ) {
245
+ return super .submit (new DelegatingErrorHandlingCallable <>(task , this .errorHandler ));
246
+ }
247
+
248
+ @ SuppressWarnings ("deprecation" )
249
+ @ Override
250
+ public ListenableFuture <?> submitListenable (Runnable task ) {
251
+ return super .submitListenable (TaskUtils .decorateTaskWithErrorHandler (task , this .errorHandler , false ));
252
+ }
253
+
254
+ @ SuppressWarnings ("deprecation" )
255
+ @ Override
256
+ public <T > ListenableFuture <T > submitListenable (Callable <T > task ) {
257
+ return super .submitListenable (new DelegatingErrorHandlingCallable <>(task , this .errorHandler ));
258
+ }
259
+
214
260
@ Override
215
261
@ Nullable
216
262
public ScheduledFuture <?> schedule (Runnable task , Trigger trigger ) {
217
263
try {
218
264
Runnable delegate = scheduledTask (task );
219
- ErrorHandler errorHandler = TaskUtils .getDefaultErrorHandler (true );
265
+ ErrorHandler errorHandler =
266
+ (this .errorHandler != null ? this .errorHandler : TaskUtils .getDefaultErrorHandler (true ));
220
267
return new ReschedulingRunnable (
221
268
delegate , trigger , this .clock , this .scheduledExecutor , errorHandler ).schedule ();
222
269
}
0 commit comments