SAS 9.1.3 Integration Technologies » Developer's Guide


Application Messaging Overview
Supported Messaging Interface Versions
WebSphere MQ Configuration and Usage
Configuring WebSphere MQ with the WebSphere MQ Explorer
Polling Message Queues from the Object Spawner
Configuring Multiple Clients To Read From a Single Queue
Configuring WebSphere MQ to Trigger SAS
WebSphere MQ Interface
Writing WebSphere MQ Applications
WebSphere MQ Code Samples
WebSphere MQ CALL Routines
MSMQ Interface
Writing MSMQ Applications
MSMQ Code Samples
MSMQ Call Routines
Common Messaging Interface
Writing Applications
Using TIB/Rendezvous with the Common Interface
TIB/Rendezvous Coding Example
TIB/Rendezvous Certified Messaging Coding Example
Using a Repository with Application Messaging
SAS CALL Routines for the Common Interface
Attachment Layout for Websphere MQ and MSMQ Through Common Messaging Interface
Attachment Layout for TIB/Rendezvous
Attachment Error Handling for Common Messaging Interface
Application Messaging

Polling Message Queues from the Object Spawner

You can use the object spawner to perform message queue polling in order to monitor queues and to start SAS programs. This feature can be useful when you want to deploy the WebSphere MQ Functional Interface in high-volume, time-sensitive situations. Message queue polling is only supported for WebSphere MQ (MQSeries) and the WebSphere MQ Client (MQSeries-C).

Message queue polling is most useful for DATA step applications that receive messages from an MQSeries message queue, and for incoming messages that are independent of each other. Reply messages can be sent, but this feature should not be used to start programs that are primarily used to send messages.

The object spawner application can monitor the queue depth for a message queue, and can start additional SAS processes to process messages on the queue. Message queue polling enables the user to configure the application monitor so that new SAS sessions can be started as needed. Message queue polling enables load balancing across multiple SAS sessions. The user can configure any number of definitions to specify which queues to monitor, the transport (MQSeries or MQSeries-C), the number of messages (the queue depth) required to start a new SAS session, and the wait interval between queries. The administrator can customize the configuration so that sufficient processes are running to handle the number of messages on the queue.

When the object spawner is stopped, it sends a high-priority stop message with a unique identifier for its current session to each SAS process that it started. By setting the SASQSID in the get message options (on the MQGMO CALL routine), the MQGET call will check for this message. If the message is found, and the session IDs match, MQGET returns a return code of -2. The DATA step program must check for this, do cleanup, and close immediately upon receiving the stop message.

The corresponding parameter option for the MQGMO CALL routine is SASQSID. This option expects a value equal to the environment variable of the same name, which is a 36 character string. The environment variable can be retrieved by using the following code in a SAS DATA step:

   sid = sysget('SASQSID');

For queues that are monitored by the object spawner, the MsgDeliverySequence property must be set to Priority.

See Message Queue Polling for more information about configuring the object spawner to perform message queue polling.

Example

The following code is a sample application that you can run with the QSID feature.

   data _null_;
   length hconn hobj cc reason 8;
   length rc hod hgmo hmd hmap msglen 8;
   length parms $ 200 options $ 200 action $ 3 msg $ 200;
   length desc $ 50;

   msglen=0;
   hconn=0;
   hobj=0;
   hod=0;
   hgmo=0;
   hmd=0;
   hmap=0;

   /* Get the unique identifier set by the object spawner for this session */
   sid =  sysget('SASQSID');
   put "Spawner job started. Sid = " sid;

   qmgr="MYQMGR";
   call mqconn(qmgr, hconn, cc, reason);

   action = "GEN";
   parms="OBJECTNAME";
   objname="LOCAL";
   call mqod(hod, action, rc, parms, objname);
   if rc ^= 0 then do;
      put 'MQOD: failed with rc= ' rc;
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   options="INPUT_SHARED";
   call mqopen(hconn, hod, options, hobj, cc, reason);
   if cc ^= 0 then do;
      put 'MQOPEN: failed with reason= ' reason;
      goto exit;
   end;

   parms= "SASQSID";
   call mqgmo(hgmo, action, rc, parms, sid);
   if rc ^= 0 then do;
      put 'MQGMO: failed with rc= ' rc;
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   desc="CHAR,,100";
   call mqmap(hmap, rc, desc);
   if rc ^= 0 then do;
      put 'MQMAP: failed with rc= ' rc;
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   reason = 0;
   do until (reason = 2033);

      action = "GEN";
      call mqmd(hmd, action, rc);
      if rc ^= 0 then do;
         put 'MQMD: failed with rc= ' rc;
         msg = sysmsg();
         put msg;
      end;

      call mqget(hconn, hobj, hmd, hgmo, msglen, cc, reason);
      if cc ^= 0 then do;
         if reason = 2033 then do;
            put 'No message available';
         end;
         else do;
            if reason = -2 then do;
               /* -2 indicates that a session specific stop message has      */
               /* been received from the object spawner queue monitor        */
               /* application.  We should clean up and shutdown immediately. */
               put "MQGET: received stop message from object spawner";
               goto exit;
            end;
            else put 'MQGET: failed with reason= ' reason;
         end;
      end;
      else put 'MQGET: message received: ';

   /* Do any application specific processing of messages here. */

   if hmd ^= 0 then do;
      call mqfree(hmd);
   end;

   end; /* end do loop */

   exit:
   if hobj ^= 0 then do;
      options="NONE";
      call mqclose(hconn, hobj, options, cc, reason);
      if cc ^= 0 then do;
         put 'MQCLOSE: failed with reason= ' reason;
      end;
   end;

   if hconn ^= 0 then do;
      call mqdisc(hconn, cc, reason);
      if cc ^= 0 then do;
         put 'MQDISC: failed with reason= ' reason;
      end;
   end;

   if hod ^= 0 then do;
      call mqfree(hod);
   end;
   if hgmo ^= 0 then do;
      call mqfree(hgmo);
   end;
   if hmd ^= 0 then do;
      call mqfree(hmd);
   end;
   if hmap ^= 0 then do;
      call mqfree(hmap);
   end;

   run;