How to Run Rexx as a Batch Job



by Howard Fosdick   © 2024 RexxInfo.org


Batch Jobs

Introduction

This article tells how to run Rexx as a mainframe batch job. It relies on examples drawn from the IBM manuals.

There are 3 basic ways to run Rexx in batch:

  1. Run in MVS Batch (IRXJCL)
  2. Run in an TSO/E environment (IKJEFT01)
  3. Run in an ISPF environment (IKJEFT01 with ISPSTART)

It's not required in all cases, but I suggest you include REXX in the first line of your Rexx program.


1. Run in MVS Batch (IRXJCL)


This method is simple. But your Rexx program can not use TSO/E services, TSO commands, or most TSO/E external functions. Your Rexx program can only perform those functions available to programs running in a non-TSO/E address space.

Code your Rexx program as a member of a partitioned dataset (PDS). The dataset name is effectively your program's name.

IRXJCL is a Rexx processor, so it will be the program name on the EXEC statement. You pass it the name of your Rexx program (its PDS member name) by using the PARM keyword.

IRXJCL requires 3 DDNAMES:

  1. SYSEXEC -- the PDS where your program resides (some sites may use SYSPROC instead)
  2. SYSTSIN -- terminal input
  3. SYSTSPRT -- where terminal output is sent to

Thus a minimal job skeleton to run a Rexx program called MYPROG looks like this.


//MYJOB    JOB 'ACT101','JOEY',CLASS=J,MSGCLASS=H,NOTIFY=&SYSUID
//MVSBACH  EXEC PGM=IRXJCL,PARM='MYPROG'
//*
//SYSEXEC  DD DSN=USERID.MYREXX.EXEC,DISP=SHR
//SYSTSIN  DD DUMMY
//SYSTSPRT DD SYSOUT=*

As in all these examples, your JCL should reside in a fixed block, 80-byte record data set.

Here's a more sophisticated example. It shows how to pass an argument into the Rexx program, as well as how to provide it input data in-stream. This example is straight from the IBM manual z/OS TSO/E REXX User's Guide.


//USERIDA  JOB  'ACCOUNT,DEPT,BLDG','PROGRAMMER NAME',
// CLASS=J,MSGCLASS=H,MSGLEVEL=(1,1)
//*
//MVSBACH  EXEC PGM=IRXJCL,
//              PARM='JCLTEST Test IRXJCL'
//*                   |     | |         |
//* Name of exec      <-----> |         |
//* Argument                  <--------->
//OUTDD    DD   DSN=USERID.TRACE.OUTPUT,DISP=MOD
//SYSTSPRT DD   DSN=USERID.IRXJCL.OUTPUT,DISP=OLD
//SYSEXEC  DD   DSN=USERID.MYREXX.EXEC,DISP=SHR
//SYSTSIN  DD   *
 First line of data
 Second line of data
 Third line of data
/*
//

In this example, the program name is USERIDA, and it runs a Rexx exec called JCLTEST. JCLTEST is a member residing in the partitioned dataset as USERID.MYREXX.EXEC(JCLTEST). The argument 'TEST IRXJCL' follows the member name and is passed to that REXX program as an input parameter. The Rexx program can read in the argument through the statement:


PARSE ARG input_argument

In-stream data input is through the SYSTSIN. Output goes to SYSTSPRT (the DSN named USERID.IRXJCL.OUTPUT). If you wanted output to go to a printer instead of that dataset, you would specify something like:


//SYSTSPRT DD   SYSOUT=A


2. Run in an TSO/E environment (IKJEFT01)


This method gives a batch Rexx program all the benefits and services of running in the TSO/E environment. You obtain that by running the TSO/E batch processing program named IKJEFT01.

In this example, the batch job USERIDA runs the TSO/E processor IKJEFT01. As in the previous example, the name of the Rexx program is MYPROG. It resides in a partitioned dataset specified by SYSEXEC and named USERID.MYREXX.EXEC.

The Rexx program to run is specified in the SYSTSIN input stream. Once again, SYSTSPRT defines the output location.


//USERIDA   JOB  'ACCOUNT,DEPT,BLDG','PROGRAMMER NAME',
// CLASS=J,MSGCLASS=C,MSGLEVEL=(1,1)
//*
//TMP       EXEC PGM=IKJEFT01,DYNAMNBR=30,REGION=4096K
//SYSEXEC   DD   DSN=USERID.MYREXX.EXEC,DISP=SHR
//SYSTSPRT  DD   SYSOUT=A
//SYSTSIN   DD   *
 %MYPROG
/*
//

Instead of specifying your program name via SYSTSIN, you could code it as a PARM to the IKJEFT01 program, as in the previous IRXJCL example.

Assume that you have coded this JCL and placed it in the partitioned dataset named REXX.JCL. That data set should be defined as fixed blocked, 80-byte records. You could start it as a background job by issuing the SUBMIT command, followed by the dataset name:


SUBMIT rexx.jcl

As an alternative to IKJEFT01, you could instead run either IKJEFT1A or IKJEFT1B. The minor differences between the three programs mainly have to do with how they handle return codes and abends. For most situations, IKJEFT01 works fine.

The above JCL coding example is straight from the IBM manual z/OS TSO/E REXX User's Guide. That manual also details the minor differences between IKJEFT01, IKJEFT1A, and IKJEFT1B.


3. Run in an ISPF environment (IKJEFT01 with ISPSTART)


This method runs your batch Rexx program in an ISPF environment. That gives it all the benefits and services of ISPF -- such as ISPF panels and tables, variable management, skeletons, and more. You achieve this by running the TSO/E batch processing program IKJEFT01, as in the previous method, but this time using the ISPSTART command.

As this example shows, you start the TSO Terminal Monitoring program by running program IKJEFT01. Invoking the ISPSTART command after the SYSTSIN input DDNAME is what starts up the ISPF environment. Note how you specify your program name MYPROG as an ISPF command:


//MYJOB    JOB 'ACT101','JOEY',CLASS=J,MSGCLASS=H,NOTIFY=&SYSUID
//*
//ISPFSTP  EXEC PGM=IKJEFT01
//*
//SYSEXEC  DD DSN=USERID.MYREXX.EXEC,DISP=SHR
//ISPPLIB  DD DSN=SYS1.ISPPLIB,DISP=SHR
//ISPMLIB  DD DSN=SYS1.ISPMLIB,DISP=SHR
//ISPTLIB  DD DSN=SYS1.ISPTLIB,DISP=SHR
//ISPPROF  DD UNIT=SYSDA,SPACE=(CYL,(10,1)),
//            RECFM=FB,LRECL=80,BLKSIZE=0
//SYSTSIN  DD *
 ISPSTART CMD(MYPROG)
/*
//SYSTSPRT DD SYSOUT=*

One big requirement here is that you allocate the ISPF libraries. These include ISPPLIB (for ISPF panels), ISPMLIB (for ISPF messages), ISPTLIB (for ISPF tables), and ISPPROF (for ISPF profiles). You many have to ask your system programmer the names of these libraries if they differ from those typical shown here.

For ISPTLIB (the ISPF tables), specify a temporary data set as its first data set. If you don't, and two jobs run concurrently, one of the jobs could fail with this error message:


ISPT036 Table in use  TBOPEN issued for table ISPSPROF that is in  use, ENQUEUE failed.

Similarly, specify a temporary data set for ISPPROF (the ISPF profile). Or, if you specify an existing data set, be sure to specify a Disposition of Old (DISP=OLD). If you don't, you could get that ENQUEUE FAILED message shown above.

You'll often see additional DDNAMES included. Examples are ISPLLIB (for load modules), ISPTABL (for any output tables), and ISPLOG (to show any logged messages.)


Be Aware Of: You need to be aware of several concerns unique to batch ISPF processing.

First, remember that there is no user interaction in batch processing. So you have to handle the case where user input is required for any of the DISPLAY services (DISPLAY, TBDISPL, SELECT PANEL, SETMSG, and PQUERY).

One method is to change the DISPLAY service to use the COMMAND parameter:


stkbuf = 'END'                               
'DISPLAY PANEL('panname') COMMAND(stkbuf)'   

Or, you can alter panels to simulate an END or ENTER key by using the .RESP keyword in your panel definition:


)INIT               
  .RESP = ENTER   

It's possible to encounter an infinite loop during display processing. To prevent this, modify the ISPSTART command by adding the BDISPMAX parameter to limit the total number of displays allowed by your program. BREDIMAX ensures the dialog ends after a specified number of redisplays:


ISPSTART CMD(SERVPAN) BDISPMAX(255)  BREDIMAX(2)

You can also add ISPSTART parameters like BATSCRW (to define the screen width), and BATSCRD (to define screen depth). This command starts ISPF with proper limits to display errors, and a screen width of 132 and depth of 50:


ISPSTART CMD(SERVPAN) BATSCRW(132) BATSCRD(50) BDISPMAX(255)  BREDIMAX(2) 

EDIT is another situation that requires user input. So you must supply an initial edit macro to provide the input that would normally be supplied by the user. Be sure to end the macro with an ISREDIT END or ISREDIT CANCEL statement. This ensures that the edit screen is not displayed. Otherwise, you could have an infinite loop.


Abend 998: If you get an Abend 998, check that:

  • All required libraries are allocated
  • All ISPF data element libraries can be opened
  • Data element libraries have valid data set characteristics
  • All literals modules can be loaded (ISRNLxxx and ISPNLxxx)
  • ISPF is not being called recursively

For further information on running Rexx programs with ISPF capabilities, see this IBM Support memo.


====> Like this article? Spread the link love to Slashdot, LXer, or wherever. Thanks!.