mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-15 11:58:34 +08:00
fix(scheduling): cancel unstarted delayed jobs during shutdown
This commit is contained in:
parent
3843dc04b7
commit
511b689387
@ -41,6 +41,9 @@ public class SchedulingConfig implements SchedulingConfigurer {
|
|||||||
scheduler.setPoolSize(POOL_SIZE);
|
scheduler.setPoolSize(POOL_SIZE);
|
||||||
scheduler.setThreadNamePrefix("sched-");
|
scheduler.setThreadNamePrefix("sched-");
|
||||||
scheduler.setRemoveOnCancelPolicy(true);
|
scheduler.setRemoveOnCancelPolicy(true);
|
||||||
|
// Pending future ticks belong to the next application lifetime. Keeping
|
||||||
|
// them queued would consume the grace period and outlive bean teardown.
|
||||||
|
scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||||
scheduler.setAwaitTerminationSeconds(30);
|
scheduler.setAwaitTerminationSeconds(30);
|
||||||
scheduler.setWaitForTasksToCompleteOnShutdown(true);
|
scheduler.setWaitForTasksToCompleteOnShutdown(true);
|
||||||
return scheduler;
|
return scheduler;
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
package vip.mate.config;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class SchedulingConfigShutdownTest {
|
||||||
|
private ThreadPoolTaskScheduler scheduler() {
|
||||||
|
var scheduler = (ThreadPoolTaskScheduler) new SchedulingConfig().taskScheduler();
|
||||||
|
scheduler.initialize();
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void futureTaskDoesNotHoldGracefulShutdownOpen() throws Exception {
|
||||||
|
var scheduler = scheduler();
|
||||||
|
var ran = new AtomicBoolean();
|
||||||
|
var pending = scheduler.schedule(() -> ran.set(true), Instant.now().plusSeconds(3600));
|
||||||
|
try (var closer = Executors.newSingleThreadExecutor()) {
|
||||||
|
try {
|
||||||
|
var closed = closer.submit(scheduler::destroy);
|
||||||
|
assertDoesNotThrow(() -> closed.get(2, TimeUnit.SECONDS),
|
||||||
|
"unstarted delayed tasks must not consume the graceful shutdown window");
|
||||||
|
assertTrue(pending.isCancelled());
|
||||||
|
assertFalse(ran.get());
|
||||||
|
} finally {
|
||||||
|
scheduler.getScheduledExecutor().shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void alreadyRunningTaskStillFinishesWithoutInterruption() throws Exception {
|
||||||
|
var scheduler = scheduler();
|
||||||
|
var started = new CountDownLatch(1);
|
||||||
|
var release = new CountDownLatch(1);
|
||||||
|
var interrupted = new AtomicBoolean();
|
||||||
|
var completed = new AtomicBoolean();
|
||||||
|
scheduler.schedule(() -> {
|
||||||
|
started.countDown();
|
||||||
|
try {
|
||||||
|
if (release.await(5, TimeUnit.SECONDS)) completed.set(true);
|
||||||
|
} catch (InterruptedException exception) {
|
||||||
|
interrupted.set(true);
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}, Instant.now());
|
||||||
|
try (var closer = Executors.newSingleThreadExecutor()) {
|
||||||
|
try {
|
||||||
|
assertTrue(started.await(2, TimeUnit.SECONDS));
|
||||||
|
var closed = closer.submit(scheduler::destroy);
|
||||||
|
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(2);
|
||||||
|
while (!scheduler.getScheduledExecutor().isShutdown() && System.nanoTime() < deadline) {
|
||||||
|
Thread.sleep(5);
|
||||||
|
}
|
||||||
|
assertTrue(scheduler.getScheduledExecutor().isShutdown());
|
||||||
|
assertFalse(closed.isDone(), "shutdown must wait for the running task");
|
||||||
|
release.countDown();
|
||||||
|
closed.get(2, TimeUnit.SECONDS);
|
||||||
|
assertTrue(completed.get());
|
||||||
|
assertFalse(interrupted.get());
|
||||||
|
} finally {
|
||||||
|
release.countDown();
|
||||||
|
scheduler.getScheduledExecutor().shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user