Writing Idempotent MQSC Scripts: The Complete Overview
Introduction
“Idempotence, in programming, is a property of an operation such that regardless how many times it has been executed, the final outcome is always the same.”
In MQ 9.2.1, all MQSC DELETE commands now feature a new parameter – IGNSTATE, which will allow the user to specify whether they want the command not to return an error code if the object that is being deleted is not present. This is another major step towards supporting idempotent MQSC command scripting, and something that numerous users have been asking for and interested in. The effort to make key MQSC commands idempotent should facilitate the scripting process for our users who would like to run their MQSC scripts repeatedly, without worrying about an error code being returned should one of the objects, that is being worked on, be in the desired state.
This blog article will provide an overview of the currently available options for MQSC commands to make them behave idempotently and will provide an example scenario of effective usage of idempotent MQSC commands.
The IGNSTATE parameter
The IGNSTATE parameter was first added to MQSC START and STOP commands in MQ 9.1.1 and has now been extended to MQSC DELETE commands as well. Broadly speaking, setting this parameter tells the command being run to ignore the current state of the object when determining if the result of the command should be reported as an error. For MQSC START commands, this means that a successful error code is returned even if the object being started is already running; for MQSC STOP commands, a successful error code is returned even if the object is already stopped. For MQSC DELETE commands, this means that a successful error code is returned even if the object being deleted does not exist. See below behaviour with and without IGNSTATE parameter:
DELETE QLOCAL(Q1) PURGE
AMQ8147E: IBM MQ object Q1 not found.
|
DELETE QLOCAL(Q1) PURGE IGNSTATE(YES)
AMQ8007I: IBM MQ queue deleted or did not exist.
|
DELETE QLOCAL(Q1) PURGE IGNSTATE(NO)
AMQ8147E: IBM MQ object Q1 not found.
|
START CHANNEL(TO.QM1)
AMQ9514E: Channel 'TO.QM1' is in use.
|
START CHANNEL(TO.QM1) IGNSTATE (YES)
AMQ8018I: Start IBM MQ channel accepted.
|
START CHANNEL(TO.QM1) IGNSTATE (NO)
AMQ9514E: Channel 'TO.QM1' is in use.
|
STOP CHANNEL(TO.QM1)
AMQ9533W: Channel 'TO.QM3' is not currently active.
|
STOP CHANNEL(TO.QM1) IGNSTATE (YES)
AMQ8019I: Stop IBM MQ channel accepted.
|
STOP CHANNEL(TO.QM1) IGNSTATE (NO)
AMQ9533W: Channel 'TO.QM3' is not currently active.
|
This parameter thus can be used to create MQSC scripts with START, STOP and DELETE commands that can be run repeatedly, for example as part of an MQSC setup or teardown script. This is especially useful, when all the user cares about is that the request has been accepted and the object’s final state is started, stopped or deleted, without consideration to what the object state previously was. For example, usually after running your script containing DELETE commands once, you would need to remove the DELETE commands because the objects will definitely be deleted after the first run – but now, with the IGNSTATE command you no longer have to worry about this.
It is also important to emphasize that genuine errors for the DELETE commands in runmqsc, e.g. a typo in one of the commands, do not get ignored – runmqsc will still return an error you can check for. For example, see example below:
1: DELETE QLOCAL(Q4 -> typo, no closing bracket.
AMQ8405I: Syntax error detected at or near end of command segment below:-
DELETE QLOCAL(Q4
AMQ8427I: Valid syntax for the MQSC command:
DELETE QLOCAL( q_name )
[ AUTHREC( YES | NO ) ]
[ PURGE | NOPURGE ]
[ IGNSTATE( YES | NO ) ]
2: DELETE QOCAL(Q4) -> typo, QLOCAL keyword mistyped.
AMQ8405I: Syntax error detected at or near end of command segment below:-
DELETE Q
AMQ8426I: Valid MQSC commands are:
DELETE AUTHINFO
DELETE AUTHREC
. . .
DELETE QLOCAL
. . .
|
The following options are available on other MQSC commands that can allow you to create fully idempotent scripts.
The REPLACE parameter
The REPLACE parameter is part of the MQSC DEFINE command and allows you to determine whether to replace the currently present definition with the incoming one. If a definition does not exist, a new one is created. See below behaviour with and without REPLACE parameter:
1: DEFINE QLOCAL(Q1)
AMQ8006I: IBM MQ queue created.
2: DEFINE QLOCAL(Q1)
AMQ8150E: IBM MQ object already exists.
|
1: DEFINE QLOCAL(Q1) REPLACE
AMQ8006I: IBM MQ queue created.
2: DEFINE QLOCAL(Q1) REPLACE
AMQ8006I: IBM MQ queue created.
|
This parameter is particularly useful when we supply different definitions to the same MQSC object, and you want to be sure that it is the latest one that is being used. Note that if there are existing messages on the queue, they do not get deleted when using the REPLACE command.
1: DEFINE QLOCAL(Q1)
AMQ8006I: IBM MQ queue created.
2: DISPLAY QUEUE(Q1) CURDEPTH
AMQ8409I: Display Queue details.
QUEUE(Q1) TYPE(QLOCAL)
CURDEPTH(4)
3: DEFINE QLOCAL(Q1) DEFBIND(OPEN) REPLACE
AMQ8006I: IBM MQ queue created.
4: DISPLAY QUEUE(Q1) CURDEPTH
AMQ8409I: Display Queue details.
QUEUE(Q1) TYPE(QLOCAL)
CURDEPTH(4)
|
Keep in mind that unlike IGNSTATE, the REPLACE parameter does not specify YES or NO attributes – the opposite of the REPLACE attribute is NOREPLACE (equivalent to when there is no REPLACE parameter specified). But, when used in the REST administration API, REPLACE does require a YES or NO value.
The PURGE parameter
This option is used together with the DELETE QLOCAL command and allows you to specify, whether the user wants to go ahead with the local queue deletion despite committed messages on that queue.
DELETE QLOCAL(Q1)
AMQ8143E: IBM MQ queue not empty.
|
DELETE QLOCAL(Q1) PURGE
AMQ8007I: IBM MQ queue deleted or did not exist.
|
The PURGE option effectively allows to skip the step of clearing the queue before deletion via the CLEAR command, saving developer time. Similar as to the REPLACE parameter, the PURGE option does not specify YES or NO attributes – the opposite of PURGE is NOPURGE and is equivalent to if there is no PURGE option specified in the command. But, when used in the REST administration API, PURGE does require a YES or NO value.
Writing Idempotent Scripts
Now that we have introduced the different options that allow us to make our MQSC scripts idempotent, let’s look at an example where this new feature could be useful. One of the use cases of such feature is the setup and teardown of queue managers for a particular configuration.
Let’s assume that we would like to setup a Uniform Cluster in our environment. An overview of Uniform Clusters is out of the scope of this blog post (see here for an overview), but one of the main distinctions of Uniform Clusters from normal IBM MQ Clusters is that every member of the Uniform Cluster has a near-identical configuration.
The following diagram shows a simple configuration of queue managers with similar configurations in a Uniform Cluster. They define the same queue called Q1 and the same server connection channel SVRCONN1:

For ease of understanding, let’s look at writing an MQSC script for a Uniform Cluster with three queue managers similar to the one in the diagram above. Let’s assume that the three queue managers have been configured in our environment before we have started and have been used for something else prior – they already have Q1 and SVRCONN1 defined, as well as some other objects, e.g. QM2 has a local queue Q2 defined as well, and QM3 has a local queue Q3 defined. See the starting configuration below:

Let’s get our environment to a similar state – we want each queue manager to just have Q1 and SVRCONN1. Instead of going in manually and deleting Q2 and Q3, we can add to our Uniform Cluster setup script:
DELETE QLOCAL(Q2) PURGE IGNSTATE(YES)
DELETE QLOCAL(Q3) PURGE IGNSTATE(YES)
We are trying to delete local queues Q2 and Q3. When this will run on QM1, which does not have Q2 or Q3 defined, we would previously have gotten an error that the objects do not exist; but now, with the new IGNSTATE parameter, we will receive a successful return code:
DELETE QLOCAL(Q2) PURGE IGNSTATE(YES)
AMQ8007I: IBM MQ queue deleted or did not exist.
Using the PURGE parameter is optional, but useful just in case we have committed messages on the queues.
Same would happen for QM2 and QM3 – if the object exists, it will be deleted, and if it doesn’t – the script will successfully continue without throwing an error. We now end up with the environment in the following state:

Next, inside our script we need to correctly setup the local queue Q1 and the server connection channel SVRCONN1. We can use the idempotent REPLACE option that we simply add to our queue manager setup script:
DEFINE CHANNEL(UNICLUSTER.+QMNAME+) CHLTYPE(CLUSRCVR) CLUSTER(+AUTOCL+) CONNAME(+CONNAME+) REPLACE
DEFINE CHANNEL(SVRCONN1) CHLTYPE(SVRCONN) MCAUSER(‘user’) REPLACE
DEFINE QLOCAL(Q1) CLUSTER(UNICLUSTER) DEFPSIST(YES) DEFBIND(NOTFIXED) REPLACE
Now all the existing definitions for Q1, the SVRCONN1 and the cluster receiver are replaced with our updated definitions.
The whole script for this scenario could look something like this:
DELETE QLOCAL(Q2) PURGE IGNSTATE(YES)
DELETE QLOCAL(Q3) PURGE IGNSTATE(YES)
DEFINE CHANNEL(UNICLUSTER.+QMNAME+) CHLTYPE(CLUSRCVR) CLUSTER(+AUTOCL+) CONNAME(+CONNAME+) REPLACE
DEFINE CHANNEL(SVRCONN1) CHLTYPE(SVRCONN) MCAUSER(‘user’) REPLACE
DEFINE QLOCAL(Q1) CLUSTER(UNICLUSTER) DEFPSIST(YES) DEFBIND(NOTFIXED) REPLACE
Hopefully this small example was useful in demonstrating how to use the new idempotent MQSC command functionality and how useful it can be in automating queue manager configuration.