From 6628bbe0befd2e7cd264ce5925114d7e323274bc Mon Sep 17 00:00:00 2001 From: jgaalen Date: Mon, 19 Jan 2026 07:48:16 +0100 Subject: [PATCH] Improve wait for delays on shutdown --- bin/jmeter.properties | 3 ++ .../apache/jmeter/threads/JMeterThread.java | 45 +++++++++++++------ xdocs/usermanual/properties_reference.xml | 4 ++ 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/bin/jmeter.properties b/bin/jmeter.properties index 58c540cfd9c..f75f3136f8f 100644 --- a/bin/jmeter.properties +++ b/bin/jmeter.properties @@ -1174,6 +1174,9 @@ cookies=cookies # How often to check for shutdown during ramp-up (milliseconds) #jmeterthread.rampup.granularity=1000 +# How often to check for shutdown during timer delay (milliseconds) +#jmeterthread.timer.granularity=1000 + #Should JMeter expand the tree when loading a test plan? # default value is false since JMeter 2.7 #onload.expandtree=false diff --git a/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java b/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java index 35f94b26982..c6498ba8cd5 100644 --- a/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java +++ b/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java @@ -80,6 +80,10 @@ public class JMeterThread implements Runnable, Interruptible { private static final int RAMPUP_GRANULARITY = JMeterUtils.getPropDefault("jmeterthread.rampup.granularity", 1000); // $NON-NLS-1$ + /** How often to check for shutdown during timer delay, default 1000ms */ + private static final int TIMER_GRANULARITY = + JMeterUtils.getPropDefault("jmeterthread.timer.granularity", 1000); // $NON-NLS-1$ + private static final float TIMER_FACTOR = JMeterUtils.getPropDefault("timer.factor", 1.0f); private static final TimerService TIMER_SERVICE = TimerService.getInstance(); @@ -998,21 +1002,36 @@ private void delay(List timers) { totalDelay += delay; } if (totalDelay > 0) { - try { - if (scheduler) { - // We reduce pause to ensure end of test is not delayed by a sleep ending after test scheduled end - // See Bug 60049 - totalDelay = TIMER_SERVICE.adjustDelay(totalDelay, endTime, false); - if (totalDelay < 0) { - log.debug("The delay would be longer than the scheduled period, so stop thread now."); - running = false; - return; + if (scheduler) { + // We reduce pause to ensure end of test is not delayed by a sleep ending after test scheduled end + // See Bug 60049 + totalDelay = TIMER_SERVICE.adjustDelay(totalDelay, endTime, false); + if (totalDelay < 0) { + log.debug("The delay would be longer than the scheduled period, so stop thread now."); + running = false; + return; + } + } + // Use granular sleeps to allow quick response to shutdown + long start = System.currentTimeMillis(); + long end = start + totalDelay; + long now; + long pause = TIMER_GRANULARITY; + while (running && (now = System.currentTimeMillis()) < end) { + long togo = end - now; + if (togo < pause) { + pause = togo; + } + try { + TimeUnit.MILLISECONDS.sleep(pause); + } catch (InterruptedException e) { + if (running) { // NOSONAR running may have been changed from another thread + log.warn("The delay timer was interrupted - Loss of delay for {} was {}ms out of {}ms", + threadName, System.currentTimeMillis() - start, totalDelay); } + Thread.currentThread().interrupt(); + break; } - TimeUnit.MILLISECONDS.sleep(totalDelay); - } catch (InterruptedException e) { - log.warn("The delay timer was interrupted - probably did not wait as long as intended."); - Thread.currentThread().interrupt(); } } } diff --git a/xdocs/usermanual/properties_reference.xml b/xdocs/usermanual/properties_reference.xml index a40ae5027a6..995daf94a6e 100644 --- a/xdocs/usermanual/properties_reference.xml +++ b/xdocs/usermanual/properties_reference.xml @@ -1484,6 +1484,10 @@ JMETER-SERVER How often to check for shutdown during ramp-up (milliseconds).
Defaults to: 1000 + + How often to check for shutdown during timer delay (milliseconds).
+ Defaults to: 1000 +
Should JMeter expand the tree when loading a test plan?
Default value is false since JMeter 2.7