|
19 | 19 |
|
20 | 20 | package org.elasticsearch.threadpool;
|
21 | 21 |
|
22 |
| -import org.apache.logging.log4j.Level; |
23 |
| -import org.apache.logging.log4j.LogManager; |
24 |
| -import org.apache.logging.log4j.Logger; |
25 |
| -import org.apache.logging.log4j.core.LogEvent; |
26 |
| -import org.elasticsearch.common.logging.Loggers; |
| 22 | +import org.elasticsearch.common.SuppressForbidden; |
27 | 23 | import org.elasticsearch.common.settings.Settings;
|
28 | 24 | import org.elasticsearch.common.unit.TimeValue;
|
29 | 25 | import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
30 | 26 | import org.elasticsearch.common.util.concurrent.EsExecutors;
|
31 | 27 | import org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor;
|
32 | 28 | import org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor;
|
33 | 29 | import org.elasticsearch.test.ESTestCase;
|
34 |
| -import org.elasticsearch.test.MockLogAppender; |
35 | 30 | import org.junit.After;
|
36 | 31 | import org.junit.Before;
|
37 | 32 |
|
38 | 33 | import java.util.Optional;
|
39 | 34 | import java.util.concurrent.CountDownLatch;
|
| 35 | +import java.util.concurrent.ExecutionException; |
40 | 36 | import java.util.concurrent.ExecutorService;
|
| 37 | +import java.util.concurrent.ScheduledFuture; |
41 | 38 | import java.util.concurrent.ScheduledThreadPoolExecutor;
|
42 | 39 | import java.util.concurrent.TimeUnit;
|
43 | 40 | import java.util.concurrent.atomic.AtomicReference;
|
| 41 | +import java.util.function.BiFunction; |
44 | 42 | import java.util.function.Consumer;
|
45 | 43 |
|
46 | 44 | import static org.hamcrest.Matchers.containsString;
|
47 |
| -import static org.hamcrest.Matchers.equalTo; |
48 | 45 | import static org.hamcrest.Matchers.hasToString;
|
49 | 46 | import static org.hamcrest.Matchers.instanceOf;
|
50 | 47 |
|
@@ -260,6 +257,50 @@ public void testExecutionExceptionOnScheduler() throws InterruptedException {
|
260 | 257 | }
|
261 | 258 | }
|
262 | 259 |
|
| 260 | + @SuppressForbidden(reason = "this tests that the deprecated method still works") |
| 261 | + public void testDeprecatedSchedule() throws ExecutionException, InterruptedException { |
| 262 | + verifyDeprecatedSchedule(((threadPool, runnable) |
| 263 | + -> threadPool.schedule(TimeValue.timeValueMillis(randomInt(10)), ThreadPool.Names.SAME, runnable))); |
| 264 | + } |
| 265 | + |
| 266 | + public void testThreadPoolScheduleDeprecated() throws ExecutionException, InterruptedException { |
| 267 | + verifyDeprecatedSchedule(((threadPool, runnable) |
| 268 | + -> threadPool.scheduleDeprecated(TimeValue.timeValueMillis(randomInt(10)), ThreadPool.Names.SAME, runnable))); |
| 269 | + } |
| 270 | + |
| 271 | + private void verifyDeprecatedSchedule(BiFunction<ThreadPool, |
| 272 | + Runnable, ScheduledFuture<?>> scheduleFunction) throws InterruptedException, ExecutionException { |
| 273 | + Thread.UncaughtExceptionHandler originalHandler = Thread.getDefaultUncaughtExceptionHandler(); |
| 274 | + CountDownLatch missingExceptions = new CountDownLatch(1); |
| 275 | + Thread.setDefaultUncaughtExceptionHandler((t, e) -> { |
| 276 | + missingExceptions.countDown(); |
| 277 | + }); |
| 278 | + try { |
| 279 | + ThreadPool threadPool = new TestThreadPool("test"); |
| 280 | + CountDownLatch missingExecutions = new CountDownLatch(1); |
| 281 | + try { |
| 282 | + scheduleFunction.apply(threadPool, missingExecutions::countDown) |
| 283 | + .get(); |
| 284 | + assertEquals(0, missingExecutions.getCount()); |
| 285 | + |
| 286 | + ExecutionException exception = expectThrows(ExecutionException.class, |
| 287 | + "schedule(...).get() must throw exception from runnable", |
| 288 | + () -> scheduleFunction.apply(threadPool, |
| 289 | + () -> { |
| 290 | + throw new IllegalArgumentException("FAIL"); |
| 291 | + } |
| 292 | + ).get()); |
| 293 | + |
| 294 | + assertEquals(IllegalArgumentException.class, exception.getCause().getClass()); |
| 295 | + assertTrue(missingExceptions.await(30, TimeUnit.SECONDS)); |
| 296 | + } finally { |
| 297 | + ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS); |
| 298 | + } |
| 299 | + } finally { |
| 300 | + Thread.setDefaultUncaughtExceptionHandler(originalHandler); |
| 301 | + } |
| 302 | + } |
| 303 | + |
263 | 304 | private Runnable delayMillis(Runnable r, int ms) {
|
264 | 305 | return () -> {
|
265 | 306 | try {
|
@@ -369,60 +410,26 @@ private void runExecutionTest(
|
369 | 410 |
|
370 | 411 | final CountDownLatch supplierLatch = new CountDownLatch(1);
|
371 | 412 |
|
372 |
| - Runnable job = () -> { |
373 |
| - try { |
374 |
| - runnable.run(); |
375 |
| - } finally { |
376 |
| - supplierLatch.countDown(); |
377 |
| - } |
378 |
| - }; |
379 |
| - |
380 |
| - // snoop on logging to also handle the cases where exceptions are simply logged in Scheduler. |
381 |
| - final Logger schedulerLogger = LogManager.getLogger(Scheduler.SafeScheduledThreadPoolExecutor.class); |
382 |
| - final MockLogAppender appender = new MockLogAppender(); |
383 |
| - appender.addExpectation( |
384 |
| - new MockLogAppender.LoggingExpectation() { |
385 |
| - @Override |
386 |
| - public void match(LogEvent event) { |
387 |
| - if (event.getLevel() == Level.WARN) { |
388 |
| - assertThat("no other warnings than those expected", |
389 |
| - event.getMessage().getFormattedMessage(), |
390 |
| - equalTo("uncaught exception in scheduled thread [" + Thread.currentThread().getName() + "]")); |
391 |
| - assertTrue(expectThrowable); |
392 |
| - assertNotNull(event.getThrown()); |
393 |
| - assertTrue("only one message allowed", throwableReference.compareAndSet(null, event.getThrown())); |
394 |
| - uncaughtExceptionHandlerLatch.countDown(); |
395 |
| - } |
396 |
| - } |
397 |
| - |
398 |
| - @Override |
399 |
| - public void assertMatched() { |
| 413 | + try { |
| 414 | + runner.accept(() -> { |
| 415 | + try { |
| 416 | + runnable.run(); |
| 417 | + } finally { |
| 418 | + supplierLatch.countDown(); |
400 | 419 | }
|
401 | 420 | });
|
| 421 | + } catch (Throwable t) { |
| 422 | + consumer.accept(Optional.of(t)); |
| 423 | + return; |
| 424 | + } |
402 | 425 |
|
403 |
| - appender.start(); |
404 |
| - Loggers.addAppender(schedulerLogger, appender); |
405 |
| - try { |
406 |
| - try { |
407 |
| - runner.accept(job); |
408 |
| - } catch (Throwable t) { |
409 |
| - consumer.accept(Optional.of(t)); |
410 |
| - return; |
411 |
| - } |
412 |
| - |
413 |
| - supplierLatch.await(); |
| 426 | + supplierLatch.await(); |
414 | 427 |
|
415 |
| - if (expectThrowable) { |
416 |
| - uncaughtExceptionHandlerLatch.await(); |
417 |
| - } |
418 |
| - } finally { |
419 |
| - Loggers.removeAppender(schedulerLogger, appender); |
420 |
| - appender.stop(); |
| 428 | + if (expectThrowable) { |
| 429 | + uncaughtExceptionHandlerLatch.await(); |
421 | 430 | }
|
422 | 431 |
|
423 | 432 | consumer.accept(Optional.ofNullable(throwableReference.get()));
|
424 |
| - } catch (IllegalAccessException e) { |
425 |
| - throw new RuntimeException(e); |
426 | 433 | } finally {
|
427 | 434 | Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
|
428 | 435 | }
|
|
0 commit comments