public final void awaitAsyncTasks() throws Exception {
            final long maxWaitTimeMillis = 600_000L;
            final long startTimeMillis = System.currentTimeMillis();
            synchronized (taskMonitor) {
                while (!pendingTasks.isEmpty()) {
                    final long currentTimeMillis = System.currentTimeMillis();
                    final long timeElapsedMillis = currentTimeMillis - startTimeMillis;
                    if (timeElapsedMillis >= maxWaitTimeMillis) {
                        throw new IllegalStateException(
                                "Wait timed out, still have the following pending tasks: " + pendingTasks);
                    }
                    final long waitTimeMillis = maxWaitTimeMillis - timeElapsedMillis;
                    taskMonitor.wait(waitTimeMillis);
                }
            }
            executor.shutdown();
            final boolean haltedCleanly = executor.awaitTermination(600, TimeUnit.SECONDS);
            if (!haltedCleanly) {
                throw new IllegalStateException("Some tasks did not finish. executor=" + executor);
            }
            synchronized (taskMonitor) {
                if (taskException != null) {
                    throw new Exception("Task threw exception", taskException);
                }
            }
        }
Wrapper around CountDownLatch for single-occurrence events.
jdisc_core/src/main/java/com/yahoo/jdisc/test/ServerProviderConformanceTest.java