Showing posts with label MQ. Show all posts
Showing posts with label MQ. Show all posts

Friday, July 10, 2026

Coordinating Db2 and MQ Updates Using RRS in a COBOL Batch Program

When a batch COBOL program performs INSERT, UPDATE, or DELETE operations on a Db2 table and also executes MQPUT operations to an IBM MQ queue, the commit/rollback processing becomes more complex.

In such a scenario, issuing a Db2 COMMIT commits only the Db2 changes; it does not commit the MQ messages. Similarly, issuing MQCMIT commits only the MQ operations and has no effect on pending Db2 updates. Each resource manager commits its own work independently but does not coordinate with other resource managers.

This is where Resource Recovery Services (RRS) becomes essential.

RRS acts as a central transaction coordinator for resource managers such as Db2 and IBM MQ. When an application requests a commit or rollback, RRS coordinates all participating resource managers using the standard two-phase commit protocol, ensuring that updates across all resources are committed or rolled back as a single unit of work.

The following sample COBOL program updates both Db2 and MQ resources and uses the RRS services to commit the changes atomically.

Unlike a traditional batch Db2 COBOL program, an application that uses RRS must explicitly establish and terminate the Db2 connection and thread within the program itself.

When we compile the program, we need to add "ATTACH(RRSAF)" option in the DB2 precompiler step. This instructs Db2 to use the RRS Attachment Facility (RRSAF) for transaction coordination.

After doing all the DB2, MQ updates, COBOL program need to invoke RSS API "SRRCMIT" to initiate the two phase COMMIT process.     

The following RSS Adapter/stub modules must be link-edited to the COBOL module:

CSQBRSTB - MQ RRS Adapter available in MQ SCSQLOAD library
DSNRLI   - DB2 RRS Adapter available in Db2 SDSNLOAD library
ATRSCSS  - available in SYS1.CSSLIB library

Since the COBOL program explicitly manages the Db2 connection through RRSAF, it can be executed like a regular Batch COBOL program.

Below is the sample run JCL.

//STEP01 EXEC PGM=DB2MQPGM,                              
//STEPLIB  DD DSN=xxxx.DB2.SDSNEXIT,DISP=SHR          
//         DD DSN=xxxx.DB2.SDSNLOAD,DISP=SHR          
//         DD DSN=xxxx.MQ.SCSQANLE,DISP=SHR            
//         DD DSN=xxxx.MQ.SCSQAUTH,DISP=SHR            
//         DD DSN=USER.LOADLIB,DISP=SHR                  
//*                                                      
//SYSOUT   DD SYSOUT=*                                    

Below is the sample COBOL program that invoke RRS services to commit the changes in both DB2 and MQ.

       IDENTIFICATION DIVISION.
       PROGRAM-ID.    DB2MQPGM.
       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01 RRSAF-FIELDS.
      * DB2 subsystem name for IDENTIFY
           05 SSNM          PIC X(04).
      * Correlation ID for SIGNON
           05 CORRID        PIC X(12).
      * Accounting token for SIGNON
           05 ACCTTKN       PIC X(22).
      * Accounting interval for SIGNON
           05 ACCTINT       PIC X(06).
      * DB2 plan name for CREATE THREAD
           05 PLAN          PIC X(08).
      * Collection ID for CREATE THREAD.
      * IF PLAN contains a plan name, not used.
           05 COLLID        PIC X(18).
      * Controls SIGNON after CREATE THREAD
           05 REUSE         PIC X(08).
      *  Action that application takes based
      *  on return code from RRSAF
           05 CONTROL1      PIC X(08).
      ****************** VARIABLES SET BY DB2 *******************************
      *  DB2 startup ECB
           05 STARTECB      PIC X(04).
      *  DB2 termination ECB
           05 TERMECB       PIC X(04).
      *  Address of environment info block
           05 EIBPTR        PIC X(04).
      *  Address of release info block
           05 RIBPTR        PIC X(04).
      ****************************** CONSTANTS ******************************
      * CONTROL value: Everything OK
           05 CONTINUE1     PIC X(08) VALUE 'CONTINUE'.
      * Name of RRSAF servicS
           05 IDFYFN        PIC X(18) VALUE 'IDENTIFY'.
           05 SGNONFN       PIC X(18) VALUE 'SIGNON'.
           05 CRTHRDFN      PIC X(18) VALUE 'CREATE THREAD'.
           05 TRMTHDFN      PIC X(18) VALUE 'TERMINATE THREAD'.
           05 TMIDFYFN      PIC X(18) VALUE 'TERMINATE IDENTIFY'.
           05 XLATFN        PIC X(18) VALUE 'TRANSLATE'.
           05 RETCODE       PIC X(04).
           05 REASCODE      PIC X(04).

       01  WS-WORK-AREAS.
           05  WS-ERROR-CODE            PIC S9(04)  VALUE ZEROS COMP.
           05  PROCESS-REC-COUNT        PIC S9(4) COMP.

       01 WS-SQLCODE                      PIC ----9.
           EXEC SQL
             INCLUDE SQLCA
           END-EXEC.

        01 OUT-MSG-LEN              PIC S9(9) COMP.

        01 MQ-Q-NAME              PIC X(48)      VALUE SPACES.
        01 MQ-HOBJ                PIC S9(9) COMP VALUE 0.
        01 MQ-OPEN-OPTS           PIC S9(9) COMP VALUE 0.
        01 MQ-CLOSE-OPTS          PIC S9(9) COMP VALUE 0.

        01 MQ-CONSTANTS.
            COPY CMQV.
        01 MQ-OBJ-DESC.
            COPY CMQODV.
        01 MQ-MSG-DESC.
            COPY CMQMDV.
        01 MQ-PUT-MSG-OPTS.
            COPY CMQPMOV.
        01 MQ-GET-MSG-OPTS.
            COPY CMQGMOV.

      * -------------------------------------------------------
      * Queue manager connection name and handle...
      * -------------------------------------------------------
        01 MQ-QM-NAME               PIC X(48)      VALUE SPACES.
        01 MQ-HCONN                 PIC S9(9) COMP-5.
        01 MQ-PROC                  PIC X(08).

      * -------------------------------------------------------
      * Queue manager op return codes and like things...
      * -------------------------------------------------------
        01 MQ-RETURN-STUFF.
            10 MQ-RC                PIC S9(9) COMP VALUE 0.
            10 MQ-RC-N9             PIC 9(9)       VALUE 0.
            10 MQ-RSN               PIC S9(9) COMP VALUE 0.
            10 MQ-RSN-N9            PIC 9(9)       VALUE 0.
            10 MQ-MSG               PIC X(256)     VALUE SPACES.

       PROCEDURE DIVISION.
       0000-MAINLINE.

           PERFORM 1000-INITIALIZATION
              THRU 1000-INITIALIZATION-EXIT.

           PERFORM 2000-PROCESS
              THRU 2000-EXIT
             VARYING PROCESS-REC-COUNT FROM 1 BY 1
             UNTIL PROCESS-REC-COUNT > 100

           PERFORM 3000-TERMINATION
              THRU 3000-TERMINATION-EXIT.

       0000-MAINLINE-EXIT.
           GOBACK.

       1000-INITIALIZATION.

           MOVE 'XXXX'     TO MQ-QM-NAME.
           MOVE 'TEST.MQ'  TO MQ-Q-NAME.

           CALL 'MQCONN' USING
                MQ-QM-NAME
                MQ-HCONN
                MQ-RC
                MQ-RSN

           IF MQ-RC = MQCC-FAILED
              MOVE 'MQCONN'    TO MQ-PROC
              GO TO 999-ERROR
           END-IF.

           MOVE MQOO-OUTPUT            TO MQ-OPEN-OPTS
           ADD  MQOO-FAIL-IF-QUIESCING TO MQ-OPEN-OPTS
           MOVE MQOT-Q    TO MQOD-OBJECTTYPE
           MOVE MQ-Q-NAME TO MQOD-OBJECTNAME

           CALL 'MQOPEN' USING
               MQ-HCONN
               MQ-OBJ-DESC
               MQ-OPEN-OPTS
               MQ-HOBJ
               MQ-RC
               MQ-RSN

           IF MQ-RC = MQCC-FAILED
              MOVE 'MQOPEN'    TO MQ-PROC
              GO TO 999-ERROR
           END-IF.

      ****************************** IDENTIFY **********************
           MOVE 'DB2A' TO SSNM
           CALL  'DSNRLI' USING
                  IDFYFN SSNM RIBPTR EIBPTR TERMECB STARTECB
                  RETCODE REASCODE
           IF RETCODE NOT = LOW-VALUES
              DISPLAY IDFYFN RETCODE REASCODE
              CALL  'DSNRLI' USING XLATFN SQLCA RETCODE REASCODE
              MOVE SQLCODE   TO WS-SQLCODE
              DISPLAY ' IDENTIFY ' WS-SQLCODE SQLERRM
           END-IF
      ***************************** SIGNON *************************
           CALL  'DSNRLI' USING
                  SGNONFN CORRID ACCTTKN ACCTINT
                  RETCODE REASCODE
           IF RETCODE NOT = LOW-VALUES
              DISPLAY SGNONFN RETCODE REASCODE
              CALL  'DSNRLI' USING XLATFN SQLCA RETCODE REASCODE
              MOVE SQLCODE   TO WS-SQLCODE
              DISPLAY 'SIGNON    ' WS-SQLCODE SQLERRM
           END-IF
      *************************** CREATE THREAD ********************
           MOVE 'TESTPLAN' TO PLAN
           CALL  'DSNRLI' USING
                  CRTHRDFN PLAN COLLID REUSE
                  RETCODE REASCODE.
           IF RETCODE NOT = LOW-VALUES
              DISPLAY CRTHRDFN RETCODE REASCODE
              CALL  'DSNRLI' USING XLATFN SQLCA RETCODE REASCODE
              MOVE SQLCODE   TO WS-SQLCODE
              DISPLAY 'CRE THRD  ' WS-SQLCODE SQLERRM
           END-IF.

       1000-INITIALIZATION-EXIT.
           EXIT.

       2000-PROCESS.

           EXEC SQL
               INSERT INTO TEST_TABLE
               ..............
               ..............  
           END-EXEC
 
           IF SQLCODE NOT = ZERO
              MOVE SQLCODE   TO WS-SQLCODE
              DISPLAY ' INSERT FAILED ' WS-SQLCODE
              PERFORM 9000-ABEND THRU 9000-ABEND-EXIT
           END-IF.

           COMPUTE MQPMO-OPTIONS
                 = MQPMO-FAIL-IF-QUIESCING
                 + MQPMO-SYNCPOINT

           MOVE LENGTH OF DATA-TO-BE-INSERTED
              TO OUT-MSG-LEN

           CALL 'MQPUT' USING
                MQ-HCONN
                MQ-HOBJ
                MQ-MSG-DESC
                MQ-PUT-MSG-OPTS
                OUT-MSG-LEN
                DATA-TO-BE-INSERTED
                MQ-RC
                MQ-RSN

           IF MQ-RC = MQCC-FAILED
              MOVE 'MQPUT'     TO MQ-PROC
              GO TO 999-ERROR
           END-IF.

       2000-EXIT.
           EXIT.


       3000-TERMINATION.

           CALL 'SRRCMIT' USING RETCODE
           DISPLAY 'SRRCMIT : ' RETCODE
      *    call 'SRRBACK' USING RETCODE
      *    DISPLAY 'SRRBACK : ' RETCODE

           CALL 'MQCLOSE' USING
               MQ-HCONN
               MQ-HOBJ
               MQ-CLOSE-OPTS
               MQ-RC
               MQ-RSN.

           IF MQ-RC = MQCC-FAILED
              DISPLAY 'MQCLOSE'
              DISPLAY 'MQ-RC: ' MQ-RC
           END-IF.

            CALL 'MQDISC' USING
                 MQ-HCONN
                 MQ-RC
                 MQ-RSN.

           IF MQ-RC = MQCC-FAILED
              DISPLAY 'MQDISC'
              DISPLAY 'MQ-RC: ' MQ-RC
           END-IF.

      ************************ TERMINATE THREAD ***********************
            CALL  'DSNRLI' USING TRMTHDFN
                   RETCODE REASCODE
            IF RETCODE NOT = LOW-VALUES
               DISPLAY TRMTHDFN RETCODE REASCODE
               CALL  'DSNRLI' USING XLATFN SQLCA RETCODE REASCODE
               MOVE SQLCODE   TO WS-SQLCODE
               DISPLAY 'TRM THRD  ' WS-SQLCODE SQLERRM
            END-IF.
      ************************ TERMINATE IDENTIFY *********************
            CALL  'DSNRLI' USING TMIDFYFN
                   RETCODE REASCODE.
            IF RETCODE NOT = LOW-VALUES
               DISPLAY TMIDFYFN RETCODE REASCODE
               CALL  'DSNRLI' USING XLATFN SQLCA RETCODE REASCODE
               MOVE SQLCODE   TO WS-SQLCODE
               DISPLAY 'TRM IDNTY ' WS-SQLCODE SQLERRM
            END-IF.

       3000-TERMINATION-EXIT.
           EXIT.


       9000-ABEND.

           CALL 'ILBOABN0' USING WS-ERROR-CODE.

       9000-ABEND-EXIT.
           EXIT.

       999-ERROR.
           MOVE MQ-RSN    TO MQ-RSN-N9
           DISPLAY 'MQ-PROC: ' MQ-PROC
           DISPLAY 'MQ-RSN : ' MQ-RSN-N9
           GOBACK.

Monday, June 29, 2026

How a Mainframe COBOL program misused MQ queue

I came across a Mainframe COBOL program reading messages one by one from MQ eueue, and does some processing and writes the output data to another MQ queue.  It is a very simple program.

The read was destructive MQGET and MQPUT was done using MQPMO_NO_SYNCPOINT so messages were written to the output MQ queue immediately. 

When I checked with application SMEs Why this program was designed this way instead of using plain sequential files.

The answer: restartability.  If this program abends, you simply restart the program, no clean up is needed.

This kind of approach can significantly increase Mainframe CPU utilization and place additional load on the MQ subsystem.

Sunday, May 25, 2025

Generate MQ, CICS related reports using CA Explore Report writer

 We can use CA Explore Report writer to generate Various sub system reports such as CICS, MQ, MVS, IMS etc from Sysview Log streams.

The below sample job gerenates "MQ OBJECT STATISTICS" from Sysview MQ log stream

//***************************************************************       
//* You can use logstreams as input:                            *       
//*                                                             *       
//* SET SMFIN='sysview.AUDIT.ADTT'                              *       
//* SET SMFIN='sysview.CICSLOGR.TRAN'                           *       
//* SET SMFIN='sysview.CICSLOGR.TSUM'                           *       
//* SET SMFIN='sysview.CICSLOGR.SYSD'                           *       
//* SET SMFIN='sysview.CICSLOGR.XLOG'                           *       
//* SET SMFIN='sysview.IMSLOGR.IMTR'                            *       
//* SET SMFIN='sysview.IMSLOGR.IMRS'                            *       
//* SET SMFIN='sysview.MQSDATA.MQHR'                            *       
//* SET SMFIN='sysview.SMFDATA.SMFD'                            *       
//* SET SMFIN='sysview.SYSDATA.XLOG'                            *       
//*                                                             *       
//* Type LGLOGS command in SYSVIEW to find out names of the     *       
//* logstreams.                                                 *       
//*                                                             *       
//***************************************************************       
//* Type Sysview high level qualifier below.                    *       
//***************************************************************       
// SET SMFIN='XXX0150.MQSDATA.MQHR'          
// SET SYSVIEW='CA.SYSVIEW.R17'                                        
//*                                                                     
//REPORT   EXEC PGM=XPFRMAIN,REGION=4M                                  
//STEPLIB  DD DISP=SHR,DSN=&SYSVIEW..CNM4BLOD                           
//ERPTPRM  DD DISP=SHR,DSN=&SYSVIEW..CNM4RSAM                           
//SYSUDUMP DD SYSOUT=*                                                  
//SYSPRINT DD DSN=USERID.MQ.SYSVIEW.TEST,                              
//            DISP=(NEW,CATLG,DELETE),                                  
//            SPACE=(CYL,(50,50)),                                      
//            DCB=(RECFM=FB,LRECL=1024)                                 
//TAPSMF   DD DISP=SHR,DSN=&SMFIN,                              *       
//            SUBSYS=(LOGR,GSVXLGEX,                            *       
//            'FROM=OLDEST,TO=YOUNGEST,LOCAL',                  *       
//            'STATS,EXPAND,BACKWARD,NORDW'),                   *       
//            DCB=(DSORG=PS,RECFM=VB,LRECL=32756,BLKSIZE=32760) *       
//*                                                             *       
//SYSIN    DD DISP=SHR,DSN=&SYSVIEW..CNM4RSAM(MQ001)               
//*                                                                
//***************************************************************  
//* Use this utility to transform created report to CSV format. *  
//*                                                             *  
//* Optional parameters: (one character long only)              *  
//*  - VS - Value Separator (default is ,)                      *  
//*  - DS - Decimal Separator (default is .)                    *  
//*                                                             *  
//***************************************************************  
//*                                                                
//PARSE    EXEC PGM=IKJEFT01                                       
//SYSEXEC  DD DISP=SHR,DSN=&SYSVIEW..CNM4RSAM                      
//SYSTSPRT DD SYSOUT=*                                             
//RWO      DD SYSOUT=*,DCB=(RECFM=FB,LRECL=1024)                   
//CSVIN    DD DSN=USERID.MQ.SYSVIEW.TEST,DISP=SHR                 
//CSVOUT   DD DSN=USERID.MQ.SYSVIEW.TEST.CSV,  
//            DISP=(NEW,CATLG,DELETE),          
//            SPACE=(CYL,(50,50)),              
//            DCB=(RECFM=FB,LRECL=1024)         
//SYSTSIN  DD *                                 
  CSVGEN CSVIN CSVOUT VS=; DS=,                 
/*                                              


The sample control cards to generate various reports can be found at 
sysview.CNM4RSAM($$INDEX) library

The below job generates last 1 hour "CICS Transaction Detail Report" from Sysview CICS logstream  

// SET SMFIN='XXXX150.CICSLOGR.TRAN'      
// SET SYSVIEW='CA.SYSVIEW.R17'                                    
//*                                                                 
//REPORT   EXEC PGM=XPFRMAIN,REGION=4M                              
//STEPLIB  DD DISP=SHR,DSN=&SYSVIEW..CNM4BLOD                       
//ERPTPRM  DD DISP=SHR,DSN=&SYSVIEW..CNM4RSAM                       
//SYSUDUMP DD SYSOUT=*                                              
//*YSPRINT DD SYSOUT=*                                              
//SYSPRINT DD DSN=USERID.CICS.SYSVIEW.TEST,                        
//            DISP=(NEW,CATLG,DELETE),                              
//            SPACE=(CYL,(50,50)),                                  
//            DCB=(RECFM=FB,LRECL=1024)                             
//TAPSMF   DD DISP=SHR,DSN=&SMFIN,                              *   
//            SUBSYS=(LOGR,GSVXLGEX,'LOCAL,DURATION=(1,HOURS)'),    
//            DCB=BLKSIZE=32760                                     
//SYSIN    DD DISP=SHR,DSN=&SYSVIEW..CNM4RSAM(CICS031)   
//PARSE    EXEC PGM=IKJEFT01                          
//SYSEXEC  DD DISP=SHR,DSN=&SYSVIEW..CNM4RSAM         
//SYSTSPRT DD SYSOUT=*                                
//RWO      DD SYSOUT=*,DCB=(RECFM=FB,LRECL=1024)      
//CSVIN    DD DSN=USERID.CICS.SYSVIEW.TEST,DISP=SHR  
//CSVOUT   DD DSN=USERID.CICS.SYSVIEW.TEST.CSV,      
//            DISP=(NEW,CATLG,DELETE),                
//            SPACE=(CYL,(50,50)),                    
//            DCB=(RECFM=FB,LRECL=1024)               
//SYSTSIN  DD *                                       
  CSVGEN CSVIN CSVOUT VS=; DS=,                       
/*                                                    

Documentation for Sample reports can be found at https://techdocs.broadcom.com/us/en/ca-mainframe-software/performance-and-storage/ca-sysview-performance-management/17-0/reporting/using-ca-explore-report-writer/sample-reports/cics-sample-reports.html

Thursday, September 2, 2021

CPU chargeback for MQ activity

Most MQ work is done under the user's TCB (i.e. in a Batch or CICS address space) and is hence charged to the Batch or CICS job. Some work, such as Commit processing, is done on a SRB or TCB within the QMgrand hence gets charged to the QMgraddress space.

Wednesday, March 1, 2017

MQ : Conditions for a trigger event

The queue manager creates a trigger message when the following conditions are satisfied:
  1. 1. A message is put on a queue.
  2. 2. The message has a priority greater than or equal to the threshold trigger priority of the queue. This priority is set in the TriggerMsgPriority local queue attribute; if it is set to zero, any message qualifies.
  3. 3. The number of messages on the queue with priority greater than or equal to TriggerMsgPriority was previously, depending on TriggerType:
    • Zero (for trigger type MQTT_FIRST)
    • Any number (for trigger type MQTT_EVERY)
    • TriggerDepth minus 1 (for trigger type MQTT_DEPTH)
    Note
    1. a. For non-shared local queues, the queue manager counts both committed and uncommitted messages when it assesses whether the conditions for a trigger event exist. Consequently an application might be started when there are no messages for it to retrieve because the messages on the queue have not been committed. In this situation, consider using the wait option with a suitable WaitInterval, so that the application waits for its messages to arrive.
    2. b. For local shared queues, the queue manager counts committed messages only.
  4. 4. For triggering of type FIRST or DEPTH, no program has the application queue open for removing messages (that is, the OpenInputCount local queue attribute is zero).
    Note
    1. a. For shared queues, special conditions apply when multiple queue managers have trigger monitors running against a queue. In this situation, if one or more queue managers have the queue open for input shared, the trigger criteria on the other queue managers are treated as TriggerType MQTT_FIRST and TriggerMsgPriority zero. When all the queue managers close the queue for input, the trigger conditions revert to those conditions specified in the queue definition.
      An example scenario affected by this condition is multiple queue managers QM1, QM2, and QM3 with a trigger monitor running for an application queue A. A message arrives on A satisfying the conditions for triggering, and a trigger message is generated on the initiation queue. The trigger monitor on QM1 gets the trigger message and triggers an application. The triggered application opens the application queue for shared input. From this point on the trigger conditions for application queue A are evaluated as TriggerType MQTT_FIRST, and TriggerMsgPriority zero on queue managers QM2 and QM3, until QM1 closes the application queue.
    2. b. For shared queues, this condition is applied for each queue manager. That is, a queue manager's OpenInputCountfor a queue must be zero for a trigger message to be generated for the  queue by that queue manager. However, if any queue manager in the queue-sharing group has the queue open using the MQOO_INPUT_EXCLUSIVE option, no trigger message is generated for that queue by any of the queue managers in the queue-sharing group.
      The change in how the trigger conditions are evaluated occurs when the triggered application opens the queue for input. In scenarios where there is only one trigger monitor running, other applications can have the same effect because they similarly open the application queue for input. It does not matter whether the application queue was opened by an application that is started by a trigger monitor, or by some other application; it is the fact that the queue is open for input on another queue manager that causes the change in trigger criteria.
  5. 5. On WebSphere MQ for z/OS, if the application queue is one with a Usage attribute of MQUS_NORMAL, get requests for it are not inhibited (that is, the InhibitGet queue attribute is MQQA_GET_ALLOWED). Also, if the triggered application queue is one with a Usage attribute of MQUS_XMITQ, get requests for it are not inhibited.
  6. 6. Either:
    • The ProcessName local queue attribute for the queue is not blank, and the process definition object identified by that attribute has been created, or
    • The ProcessName local queue attribute for the queue is all blank, but the queue is a transmission queue. As the process definition is optional, the TriggerData attribute might also contain the name of the channel to be started. In this case, the trigger message contains attributes with the following values:
      • QName: queue name
      • ProcessName: blanks
      • TriggerData: trigger data
      • ApplType: MQAT_UNKNOWN
      • ApplId: blanks
      • EnvData: blanks
      • UserData: blanks
  7. 7. An initiation queue has been created, and has been specified in the InitiationQName local queue attribute. Also:
    • Get requests are not inhibited for the initiation queue (that is, the InhibitGet queue attribute is MQQA_GET_ALLOWED).
    • Put requests must not be inhibited for the initiation queue (that is, the InhibitPut queue attribute must be MQQA_PUT_ALLOWED).
    • The Usage attribute of the initiation queue must be MQUS_NORMAL.
    • In environments where dynamic queues are supported, the initiation queue must not be a dynamic queue that has been marked as logically deleted.
  8. 8. A trigger monitor currently has the initiation queue open for removing messages (that is, the OpenInputCount local queue attribute is greater than zero).
  9. 9. The trigger control (TriggerControl local queue attribute) for the application queue is set to MQTC_ON. To do this, set the trigger attribute when you define your queue, or use the ALTER QLOCAL command.
  10. 10. The trigger type (TriggerType local queue attribute) is not MQTT_NONE.
    If all the required conditions are met, and the message that caused the trigger condition is put as part of a unit of work, the trigger message does not become available for retrieval by the trigger monitor application until the unit of work completes, whether the unit of work is committed or, for trigger type MQTT_FIRST or MQTT_DEPTH, backed out.
  11. 11. A suitable message is placed on the queue, for a TriggerType of MQTT_FIRST or MQTT_DEPTH, and the queue:
    • Was not previously empty (MQTT_FIRST), or
    • Had TriggerDepth or more messages (MQTT_DEPTH)
    and conditions 2 through 10 (excluding 3) are satisfied, if in the case of MQTT_FIRST a sufficient interval (TriggerIntervalqueue-manager attribute) has elapsed since the last trigger message was written  for this queue.
    This is to allow for a queue server that ends before processing all the messages on the queue. The purpose of the trigger interval is to reduce the number of duplicate trigger messages that are generated.
    Note
    If you stop and restart the queue manager, the TriggerInterval timer is reset. There is a small window during which it is possible to produce two trigger messages. The window exists when the trigger attribute of the queue is set to enabled at the same time as a message arrives and the queue was not previously empty (MQTT_FIRST) or had TriggerDepth or more messages (MQTT_DEPTH).
  12. 12. The only application serving a queue issues an MQCLOSE call, for a TriggerType of MQTT_FIRST or MQTT_DEPTH, and there is at least:
    • One (MQTT_FIRST), or
    • TriggerDepth (MQTT_DEPTH)
    messages on the queue of sufficient priority (condition 2), and conditions 6 through 10 are also satisfied.
    This is to allow for a queue server that issues an MQGET call, finds the queue empty, and so ends; however, in the interval between the MQGET and the MQCLOSE calls, one or more messages arrive.
    Note
    1. a. If the program serving the application queue does not retrieve all the messages, this can cause a closed loop. Each time that the program closes the queue, the queue manager creates another trigger message that causes the trigger monitor to start the server program again.
    2. b. If the program serving the application queue backs out its get request (or if the program abends) before it closes the queue, the same happens. However, if the program closes the queue before backing out the get request, and the queue is otherwise empty, no trigger message is created.
    3. c. To prevent such a loop occurring, use the BackoutCount field of MQMD to detect messages that are repeatedly backed out. For more information, see Messages that are backed out.
  13. 13. The following conditions are satisfied using MQSET or a command:
      • TriggerControl is changed to MQTC_ON, or
      • TriggerControl is already MQTC_ON and the value of either TriggerType, TriggerMsgPriority, or TriggerDepth (if relevant) is changed,
      and there is at least:
      • One (MQTT_FIRST or MQTT_EVERY), or
      • TriggerDepth (MQTT_DEPTH)
      messages on the queue of sufficient priority (condition 2), and conditions 4 through 10 (excluding 8) are also satisfied.
      This is to allow for an application or operator changing the triggering criteria, when the conditions for a trigger to occur are already satisfied.
    1. The InhibitPut queue attribute of an initiation queue changes from MQQA_PUT_INHIBITED to MQQA_PUT_ALLOWED, and there is at least:
      • One (MQTT_FIRST or MQTT_EVERY), or
      • TriggerDepth (MQTT_DEPTH)
      messages of sufficient priority (condition 2) on any of the queues for which this is the initiation queue, and conditions 4 through 10 are also satisfied. (One trigger message is generated for each such queue satisfying the conditions.)
      This is to allow for trigger messages not being generated because of the MQQA_PUT_INHIBITED condition on the initiation queue, but this condition now having been changed.
    2. The InhibitGet queue attribute of an application queue changes from MQQA_GET_INHIBITED to MQQA_GET_ALLOWED, and there is at least:
      • One (MQTT_FIRST or MQTT_EVERY), or
      • TriggerDepth (MQTT_DEPTH)
      messages of sufficient priority (condition 2) on the queue, and conditions 4 through 10, excluding 5, are also satisfied.
      This allows applications to be triggered only when they can retrieve messages from the application queue.
    3. A trigger-monitor application issues an MQOPEN call for input from an initiation queue, and there is at least:
      • One (MQTT_FIRST or MQTT_EVERY), or
      • TriggerDepth (MQTT_DEPTH)
      messages of sufficient priority (condition 2) on any of the application queues for which this is the initiation queue, and conditions 4 through 10 (excluding 8) are also satisfied, and no other application has the initiation queue open for input (one trigger message is generated for each such queue satisfying the conditions).
      This is to allow for messages arriving on queues while the trigger monitor is not running, and for the queue manager restarting and trigger messages (which are nonpersistent) being lost.
  14. 14. MSGDLVSQ is set correctly. If you set MSGDLVSQ=FIFO, messages are delivered to the queue in a First In First Out basis. The priority of the message is ignored and the default priority of the queue is assigned to the message. If TriggerMsgPriority is set to a higher value than the default priority of the queue, no messages are triggered. If TriggerMsgPriority is set equal to or lower than the default priority of the queue, triggering occurs for type FIRST, EVERY, and DEPTH. For information about these types, see the description of the TriggerType field under Controlling trigger events.
    If you set MSGDLVSQ=PRIORITY and the message priority is equal to or greater than the TriggerMsgPriority field, messages only count towards a trigger event. In this case, triggering occurs for type FIRST, EVERY, and DEPTH. As an example, if you put 100 messages of lower priority than the TriggerMsgPriority, the effective queue depth for triggering purposes is still zero. If you then put another message on the queue, but this time the priority is greater than or equal to the TriggerMsgPriority, the effective queue depth increases from zero to one and the condition for TriggerType FIRST is satisfied.
Note
  1. 1. From step 12 (where trigger messages are generated as a result of some event other than a message arriving on the application queue), the trigger message is not put as part of a unit of work. Also, if the TriggerType is MQTT_EVERY, and if there are one or more messages on the application queue, only one trigger message is generated.
  2. 2. If WebSphere MQ segments a message during MQPUT, a trigger event will not be processed until all the segments have been successfully placed on the queue. However, once message segments are on the queue, WebSphere MQ treats them as individual messages for triggering purposes. For example, a single logical message split into three pieces causes only one trigger event to be processed when it is first MQPUT and segmented. However, each of the three segments causes their own trigger events to be processed as they are moved through the WebSphere MQ network.