Skip to content

Commit

Permalink
Add non-GUI stoptest and shutdown commands
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/trunk@768083 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
sebbASF committed Apr 23, 2009
1 parent 0bfe9e2 commit 828ac54
Show file tree
Hide file tree
Showing 13 changed files with 261 additions and 41 deletions.
6 changes: 5 additions & 1 deletion bin/jmeter.properties
Original file line number Diff line number Diff line change
Expand Up @@ -648,8 +648,12 @@ beanshell.server.file=../extras/startup.bsh
# Number of milliseconds to wait for a thread to stop
#jmeterengine.threadstop.wait=5000

# If running non-GUI, then JMeter listens on the following port for a shutdown message.
# To disable, set the port to 0.
#jmeterengine.nongui.port=4445

#Should JMeter expand the tree when loading a test plan?
#onload.expandtree=false
#onload.expandtree=true

# Maximum size of HTML page that can be displayed; default=200 * 1024
# Set to 0 to disable the size check
Expand Down
21 changes: 21 additions & 0 deletions bin/shutdown.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@echo off

rem Licensed to the Apache Software Foundation (ASF) under one or more
rem contributor license agreements. See the NOTICE file distributed with
rem this work for additional information regarding copyright ownership.
rem The ASF licenses this file to You under the Apache License, Version 2.0
rem (the "License"); you may not use this file except in compliance with
rem the License. You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.

rem Run the Shutdown client

java -cp %~dp0ApacheJMeter.jar org.apache.jmeter.util.ShutdownClient Shutdown %*
pause
22 changes: 22 additions & 0 deletions bin/shutdown.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh

## Licensed to the Apache Software Foundation (ASF) under one or more
## contributor license agreements. See the NOTICE file distributed with
## this work for additional information regarding copyright ownership.
## The ASF licenses this file to You under the Apache License, Version 2.0
## (the "License"); you may not use this file except in compliance with
## the License. You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.

# Run the JMeter shutdown client

DIRNAME=`dirname $0`

java -cp ${DIRNAME}/ApacheJMeter.jar org.apache.jmeter.util.ShutdownClient Shutdown "$@"
21 changes: 21 additions & 0 deletions bin/stoptest.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@echo off

rem Licensed to the Apache Software Foundation (ASF) under one or more
rem contributor license agreements. See the NOTICE file distributed with
rem this work for additional information regarding copyright ownership.
rem The ASF licenses this file to You under the Apache License, Version 2.0
rem (the "License"); you may not use this file except in compliance with
rem the License. You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.

rem Run the Shutdown client

java -cp %~dp0ApacheJMeter.jar org.apache.jmeter.util.ShutdownClient StopTestNow %*
pause
22 changes: 22 additions & 0 deletions bin/stoptest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh

## Licensed to the Apache Software Foundation (ASF) under one or more
## contributor license agreements. See the NOTICE file distributed with
## this work for additional information regarding copyright ownership.
## The ASF licenses this file to You under the Apache License, Version 2.0
## (the "License"); you may not use this file except in compliance with
## the License. You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.

# Run the JMeter shutdown client

DIRNAME=`dirname $0`

java -cp ${DIRNAME}/ApacheJMeter.jar org.apache.jmeter.util.ShutdownClient StopTestNow "$@"
5 changes: 3 additions & 2 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ run JMeter unless all the JMeter jars are added.

<!-- JMeter launch jar -->
<jar jarfile="${dest.jar.jmeter}/ApacheJMeter.jar"
includes="**/NewDriver*,**/DynamicClassLoader*"
includes="**/NewDriver*,**/DynamicClassLoader*,**/ShutdownClient.class"
basedir="${build.core}"
manifest="${build.dir}/MANIFEST_BIN.MF">
<metainf dir="." includes="LICENSE,NOTICE"/>
Expand Down Expand Up @@ -1003,7 +1003,8 @@ run JMeter unless all the JMeter jars are added.
List of Unix executable files in the binary distribution
These need special handling to create the correct file mode
-->
<property name="dist.executables" value="${dest.jar.jmeter}/jmeter ${dest.jar.jmeter}/jmeter.sh ${dest.jar.jmeter}/jmeter-server"/>
<property name="dist.executables"
value="${dest.jar.jmeter}/jmeter ${dest.jar.jmeter}/jmeter-server ${dest.jar.jmeter}/*.sh"/>

<!-- List of files in source distribution that are eol=native -->
<patternset id="dist.sources.native">
Expand Down
Binary file modified docs/images/screenshots/test_action.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
100 changes: 76 additions & 24 deletions src/core/org/apache/jmeter/engine/StandardJMeterEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
Expand Down Expand Up @@ -59,23 +62,8 @@ public class StandardJMeterEngine implements JMeterEngine, JMeterThreadMonitor,

private static final long WAIT_TO_DIE = JMeterUtils.getPropDefault("jmeterengine.threadstop.wait", 5 * 1000); // 5 seconds

/** JMeterThread => its JVM thread */
private final Map/*<JMeterThread, Thread>*/ allThreads;

/** flag to show that groups are still being created, i.e test plan is not complete */
private volatile boolean startingGroups;

/** Flag to show whether test is running. Set to false to stop creating more threads. */
private volatile boolean running = false;

/** Thread Groups run sequentially */
private volatile boolean serialized = false;

private HashTree test;

private volatile SearchByClass testListenersSave;

private final String host;
/** UDP port used in non-GUI runs. Disabled if <=1000. */
private static final int UDP_PORT = JMeterUtils.getPropDefault("jmeterengine.nongui.port", 4445);

// Should we exit at end of the test? (only applies to server, because host is non-null)
private static final boolean exitAfterTest =
Expand All @@ -90,12 +78,38 @@ public class StandardJMeterEngine implements JMeterEngine, JMeterThreadMonitor,
log.info("To revert to the earlier behaviour, define jmeterengine.startlistenerslater=false");
}
}

// Allow engine and threads to be stopped from outside a thread
// e.g. from beanshell server
// Assumes that there is only one instance of the engine
// at any one time so it is not guaranteed to work ...
private volatile static StandardJMeterEngine engine;

/*
* Allow functions etc to register for testStopped notification.
* Only used by the function parser so far.
* The list is merged with the testListeners and then cleared.
*/
private static final List testList = new ArrayList();

/** JMeterThread => its JVM thread */
private final Map/*<JMeterThread, Thread>*/ allThreads;

/** flag to show that groups are still being created, i.e test plan is not complete */
private volatile boolean startingGroups;

/** Flag to show whether test is running. Set to false to stop creating more threads. */
private volatile boolean running = false;

/** Thread Groups run sequentially */
private volatile boolean serialized = false;

private HashTree test;

private volatile SearchByClass testListenersSave;

private final String host;

public static void stopEngineNow() {
if (engine != null) {// May be null if called from Unit test
engine.stopTest(true);
Expand All @@ -108,13 +122,6 @@ public static void stopEngine() {
}
}

/*
* Allow functions etc to register for testStopped notification.
* Only used by the function parser so far.
* The list is merged with the testListeners and then cleared.
*/
private static final List testList = new ArrayList();

public static synchronized void register(TestListener tl) {
testList.add(tl);
}
Expand Down Expand Up @@ -190,6 +197,15 @@ public void runTest() throws JMeterEngineException {
try {
Thread runningThread = new Thread(new MyThreadGroup("JMeterThreadGroup"),this);
runningThread.start();
if (JMeter.isNonGUI() && UDP_PORT > 1000){
Thread waiter = new Thread(){
public void run() {
waitForSignals();
}
};
waiter.setDaemon(true);
waiter.start();
}
} catch (Exception err) {
stopTest();
StringWriter string = new StringWriter();
Expand All @@ -199,6 +215,42 @@ public void runTest() throws JMeterEngineException {
}
}

private void waitForSignals() {
byte[] buf = new byte[80];
DatagramSocket socket = null;
System.out.println("Waiting for possible shutdown message on port "+UDP_PORT);
try {
socket = new DatagramSocket(UDP_PORT);
DatagramPacket request = new DatagramPacket(buf, buf.length);
while(true) {
socket.receive(request);
InetAddress address = request.getAddress();
// Only accept commands from the local host
if (address.isLoopbackAddress()){
String command = new String(request.getData(), request.getOffset(), request.getLength(),"ASCII");
System.out.println("Command: "+command+" received from "+address);
log.info("Command: "+command+" received from "+address);
if (command.equals("StopTestNow")){
stopTest();
break;
} else if (command.equals("Shutdown")) {
askThreadsToStop();
break;
} else {
}
}
}
socket.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}

}

private void removeThreadGroups(List elements) {
Iterator iter = elements.iterator();
while (iter.hasNext()) {
Expand Down
47 changes: 47 additions & 0 deletions src/core/org/apache/jmeter/util/ShutdownClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package org.apache.jmeter.util;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


/**
* Simple utility to send a shutdown message to a non-GUI instance of JMeter
*/
public class ShutdownClient {
public static void main(String[] args) throws IOException {
int port = 4445;
if (args.length > 1){
port = Integer.parseInt(args[1]);
} else if (args.length == 0) {
throw new RuntimeException("Usage: command [port]");
}
String command = args[0];
System.out.println("Sending "+command+" request to port "+port);
DatagramSocket socket = new DatagramSocket();
byte[] buf = command.getBytes("ASCII");
InetAddress address = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
socket.close();
}
}
1 change: 1 addition & 0 deletions xdocs/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ JMeter now removes extraneous leading "../" segments (as do many browsers)
<li>The Menu items Stop and Shutdown now behave better. Shutdown will now wait until all threads exit.
In GUI mode it can be cancelled and Stop run instead.
Stop now reports if some threads will not exit, and exits if running in non-GUI mode</li>
<li>Add UDP server to wait for shutdown message if running in non-GUI mode; add UDP client to send the message.</li>
</ul>

<h3>Non-functional changes</h3>
Expand Down
43 changes: 35 additions & 8 deletions xdocs/usermanual/build-test-plan.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,49 @@ the Edit menu.
</subsection>

<subsection name="&sect-num;.5 Running a Test Plan" anchor="run">
<p>To run your test plan, choose "start" from the "run" menu item. To stop your test
plan, choose "stop" from the same menu.
<p>To run your test plan, choose "Start" (Control + r) from the "Run" menu item.
When JMeter is running, it shows a small green box at the right hand end of the section just under the menu bar.
You can also check the "run" menu.
If "start" is disabled, and "stop" is enabled,
You can also check the "Run" menu.
If "Start" is disabled, and "Stop" is enabled,
then JMeter is running your test plan (or, at least, it thinks it is).</p>
<p>
There are two types of stop command:
The numbers to the left of the green box are the number of active threads / total number of threads.
</p>
</subsection>

<subsection name="&sect-num;.6 Stopping a Test" anchor="stop">
<p>
There are two types of stop command available from the menu:
<ul>
<li>Stop (Control + '.') - stops the threads immediately if possible.
In Versions of JMeter after 2.3.2, many samplers are now Interruptible which means that active samples can be terminated early.
The stop command will check that all threads have stopped within the default timeout, which is 5000 ms = 5 seconds.
[This can be changed using the JMeter property <code>jmeterengine.threadstop.wait</code>]
If the threads have not stopped, then a message is displayed.
The Stop command can be retried, but if it fails, then it is necessary to exit JMeter to clean up.
</li>
<li>Shutdown (Control + ',')- requests the threads to stop at the end of any current work.
Will not interrupt any active samples.
The modal shutdown dialog box will remain active until all threads have stopped.</li>
</ul>
Versions of JMeter after 2.3.2 allow a Stop to be initiated if Shutdown is taking too long.
Close the Shutdown dialog box and select Run/Stop, or just press Control + '.'.
</p>
<p>
When running JMeter in non-GUI mode, there is no Menu, and JMeter does not react to keystrokes such as Control + '.'.
So in versions after 2.3.2, JMeter non-GUI mode will listen for commands on a specific port
(default 4445, see the JMeter property <code>jmeterengine.nongui.port</code>).
The commands currently supported are:
<ul>
<li>Stop (Control + '.') - stops the threads immediately</li>
<li>Shutdown (Control + ',')- requests the threads to stop at the end of any current work</li>
<li>Shutdown - graceful shutdown</li>
<li>StopTestNow - immediate shutdown</li>
</ul>
These commands can be sent by using the <code>shutdown[.cmd|.sh]</code> or <code>stoptest[.cmd|.sh]</code> script
respectively. The scripts are to be found in the JMeter <code>bin</code> directory.
</p>
</subsection>

<subsection name="&sect-num;.6 Error reporting" anchor="error_reporting">
<subsection name="&sect-num;.7 Error reporting" anchor="error_reporting">
<p>
JMeter reports warnings and errors to the jmeter.log file, as well as some information on the test run itself.
Just occasionally there may be some errors that JMeter is unable to trap and log; these will appear on the command console.
Expand Down
4 changes: 4 additions & 0 deletions xdocs/usermanual/component_reference.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,10 @@ For variable delays, set the pause time to zero, and add a Timer as a child.</p>
<p>
The "Stop" action stops the thread or test after completing any samples that are in progress.
The "Stop Now" action stops the test without waiting for samples to complete; it will interrupt any active samples.
If some threads fail to stop within the 5 second time-limit, a message will be displayed in GUI mode.
You can try using the Stop command to see if this will stop the threads, but if not, you should exit JMeter.
In non-GUI mode, JMeter will exit if some threads fail to stop within the 5 second time limit.
[This can be changed using the JMeter property <code>jmeterengine.threadstop.wait</code>]
</p>
</description>
<properties>
Expand Down
Loading

0 comments on commit 828ac54

Please sign in to comment.