Submit Recurring Job
From MidrangeWiki
Contents
Background
If you do not have access to the Advanced Job Scheduler on the IBM i servers, this program can help you to submit a job a recurring number of times. The source consists of the following
RTVJOBCNT - CMD - Retrieve Job Count RTVJOBCN#C - CLLE - Retrieve Job Count CL Program SBMRECJOB - CMD - Submit Recurring Job SBMRECJB#C - CLLE - Submit recurring Job CL PRogram
Using the program
The program should NOT be run interactively, you should either submit this process, or schedule it in the Job Scheduler.
If you issue the command SBMRECJOB, you have to provide the following fields:
Submit Recurring Job (SBMRECJOB) Type choices, press Enter. Command to submit . . . . . . . _____________________________________________ _______________________________________________________________________________ _______________________________________________________________________________ _________________ ...
Submitted Job Name . . . . . . . ____________ Character value Submitted Job User Profile . . . *CURRENT Character value, *CURRENT Submitted Job Queue to use . . . *JOBD Name, *JOBD Library Name . . . . . . . . . *LIBL Character value, *LIBL Allow duplicate jobs? . . . . . *YES *YES, *NO Number of recurring iterations 2 1-999 Delay between iterations . . . . 60 Delay in seconds (up to 24 hr) Bottom F3=Exit F4=Prompt F5=Refresh F12=Cancel F13=How to use this display F24=More keys
- Command to submit: Specify the command here. You can also prompt the command to give the correct values and parameters
- Submitted Job name: The command specified will be submitted using the specified job name.
- Submitted Job User Profile: Under which profile should the submitted job run. Can also specify *CURRENT for the user running the current job.
- Submitted Job queue to use: Specify a jobq to use for the submission. Can also specify *JOBD to use the JOBD from the user profile
- Allow Duplicate Jobs: If there should always be only one job with this name running, use *NO here. If you do not care whether the previous job ended or not, you can ignore duplicate jobs and specify *YES here
- Number of recurring iterations: Specify how many times this job will be submitted
- Delay between iterations: Specify here how may seconds delay should take place between submissions. This behaviour is also governed by the "Allow Duplicate Jobs" parameter:
- - Allow Duplicate Jobs = *YES - Delay will be between submissions. If the delay is 60 seconds, every 60 seconds a submission will take place
- - Allow Duplicate Jobs = *NO - Delay will be xx number of seconds after the one job ended and the next one is submitted again
Source Code - SBMRECJOB
CMD PROMPT('Submit Recurring Job') PARM KWD(SBMCMD) TYPE(*CMDSTR) LEN(5000) MIN(1) + PROMPT('Command to submit') PARM KWD(SBMJOB) TYPE(*CHAR) LEN(10) MIN(1) + PROMPT('Submitted Job Name') PARM KWD(SBMUSR) TYPE(*CHAR) LEN(10) + DFT(*CURRENT) SPCVAL((*CURRENT)) + PROMPT('Submitted Job User Profile') PARM KWD(SBMJOBQ) TYPE(QUAL1) PROMPT('Submitted + Job Queue to use') PARM KWD(SBMDUP) TYPE(*CHAR) LEN(4) RSTD(*YES) + DFT(*YES) VALUES(*YES *NO) PROMPT('Allow + duplicate jobs?') PARM KWD(ITERATION) TYPE(*DEC) LEN(3 0) DFT(2) + RANGE(1 999) PROMPT('Number of recurring + iterations') PARM KWD(DELAY) TYPE(*DEC) LEN(5) DFT(60) RANGE(1 + 86400) CHOICE('Delay in seconds (up to 24 + hr)') PROMPT('Delay between iterations') hr)') PROMPT('Delay between iterations') QUAL1: QUAL TYPE(*NAME) LEN(10) DFT(*JOBD) SPCVAL((*JOBD)) QUAL TYPE(*CHAR) LEN(10) DFT(*LIBL) + SPCVAL((*LIBL)) PROMPT('Library Name')
- Compile with
CRTCMD ??CMD(SBMRECJOB) ??PGM(*LIBL/SBMRECJB#C) ?*SRCFILE(ZOPSLIB/QCMDSRC) ?*SRCMBR(SBMRECJOB) ALLOW(*BATCH *BPGM *BREXX *EXEC *BMOD) ??REPLACE(*NO)
Source Code - SBMRECJB#C
BEGIN: PGM PARM(&SBMCMD &SBMJOB &SBMUSR &SBMJOBQ + &SBMDUP &SBMITER &DELAY) /*-------------------------------------------------------------------*/ /* PASSED Variables */ /*------------------- */ /* */ DCL VAR(&SBMCMD) TYPE(*CHAR) LEN(5000) DCL VAR(&SBMJOB) TYPE(*CHAR) LEN(10) DCL VAR(&SBMUSR) TYPE(*CHAR) LEN(10) DCL VAR(&SBMJOBQ) TYPE(*CHAR) LEN(20) DCL VAR(&SBMDUP) TYPE(*CHAR) LEN(4) DCL VAR(&SBMITER) TYPE(*DEC) LEN(3 0) DCL VAR(&DELAY) TYPE(*DEC) LEN(5 0) /* */ /* PROGRAM Variables */ /*-------------------- */ /* */ DCL VAR(&COUNTER) TYPE(*INT) DCL VAR(&JOBCOUNT) TYPE(*DEC) LEN(8 0) DCL VAR(&SBMSTRING) TYPE(*CHAR) LEN(6000) DCL VAR(&ITERATION) TYPE(*INT) DCL VAR(&JOBQ) TYPE(*CHAR) LEN(10) DCL VAR(&JOBQLIB) TYPE(*CHAR) LEN(10) DCL VAR(&JOBQVAL) TYPE(*CHAR) LEN(22) /* */ /* Settings for input parameters */ /* */ /* */ /* Standard Error Handling variables */ /*------------------------------------ */ /* */ DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) /* Error + Message Identifier */ DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(256) /* Error + Message Data */ DCL VAR(&MSGFILNAM) TYPE(*CHAR) LEN(10) /* Error + Message File Name */ DCL VAR(&MSGFILLIB) TYPE(*CHAR) LEN(10) /* Error + Message File Name */ /* ----------------------------------------------------------------- */ /* Program Code Starts Here */ /* ------------------------ */ /* */ /* MONITOR FOR UNEXPECTED ERROR MESSAGES */ MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) /* */ /* */ /* Reset counters first */ /*------------------------------------------------------------ */ /* */ CHGVAR VAR(&COUNTER) VALUE(0) CHGVAR VAR(&JOBCOUNT) VALUE(0) CHGVAR VAR(&ITERATION) VALUE(&SBMITER) /* */ /* */ /* Check if the user exist, if not, retrieve current user profile */ /*------------------------------------------------------------ */ /* */ IF COND(&SBMUSR *EQ '*CURRENT') THEN(RTVJOBA + USER(&SBMUSR)) CHKOBJ OBJ(&SBMUSR) OBJTYPE(*USRPRF) MONMSG MSGID(CPF0000) EXEC(DO) RTVJOBA USER(&SBMUSR) ENDDO /* */ /* */ /* Check if the job queue exist. If not, set JOBQ to *JOBD */ /*------------------------------------------------------------ */ /* */ CHGVAR VAR(&JOBQ) VALUE(%SST(&SBMJOBQ 1 10)) CHGVAR VAR(&JOBQLIB) VALUE(%SST(&SBMJOBQ 11 10)) SELECT WHEN COND(&JOBQ *EQ '*JOBD') THEN(DO) CHGVAR VAR(&JOBQVAL) VALUE('*JOBD') ENDDO /**/ WHEN COND(&JOBQ *NE '*JOBD') THEN(DO) CHGVAR VAR(&JOBQVAL) VALUE(&JOBQLIB *TCAT '/' *TCAT + &JOBQ) CHKOBJ OBJ(&JOBQLIB/&JOBQ) OBJTYPE(*JOBQ) MONMSG MSGID(CPF0000) EXEC(DO) CHGVAR VAR(&JOBQVAL) VALUE('*JOBD') ENDDO ENDDO ENDSELECT /* */ /* */ /* Setup the command now, write entries to the joblog */ /*------------------------------------------------------------ */ /* */ CHGVAR VAR(&SBMSTRING) VALUE('SBMJOB CMD(' *TCAT + &SBMCMD *TCAT ') JOB(' *TCAT &SBMJOB + *TCAT ') USER(' *TCAT &SBMUSR *TCAT ') + CURLIB(*USRPRF) INLLIBL(*JOBD) JOBQ(' + *TCAT &JOBQVAL *TCAT ')') SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Cmd to + submit -' *BCAT %TRIM(&SBMCMD)) SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Delay + time in seconds - ' *TCAT %CHAR(&DELAY)) SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Submit + user - ' *BCAT &SBMUSR) SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Submit + job name - ' *BCAT &SBMJOB) /* */ /* */ /* Go into the for loop here. */ /*------------------------------------------------------------ */ /* */ DOFOR VAR(&COUNTER) FROM(1) TO(&ITERATION) SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) + MSGDTA('Iteration - ' *BCAT + %CHAR(&COUNTER) *BCAT 'of' *BCAT + %CHAR(&ITERATION)) /* */ /* Check if job is already running. */ /*------------------------------------------------------------ */ /* */ RTVJOBCNT JOB(&SBMJOB) USER(&SBMUSR) + COUNT(&JOBCOUNT) MONMSG MSGID(CPF0000) SELECT /* If job is not active, or Submit Duplicates is yes, submit it */ WHEN COND(&JOBCOUNT = 0 *OR &SBMDUP = '*YES') + THEN(DO) SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) + MSGDTA('-- Submitting job ' *BCAT &SBMJOB + *BCAT ' for user ' *BCAT &SBMUSR) CALL PGM(QCMDEXC) PARM(&SBMSTRING 6000) ENDDO OTHERWISE CMD(DO) SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('-- Job + ' *BCAT &SBMJOB *BCAT ' NOT submitted for + user ' *BCAT &SBMUSR) ENDDO ENDSELECT /* */ /* */ /* Delay the job now for the specified number of minutes */ /*------------------------------------------------------------ */ /* */ DLYJOB DLY(&DELAY) ENDDO /* */ /* GO TO NORMAL PROGRAM END */ /* ------------------------------------------- */ /* */ GOTO CMDLBL(EXIT) /* */ /* ----------------------------------------------------------------- */ /* UNEXPECTED ERROR ROUTINE */ /* ------------------------ */ /* */ ERROR: RCVMSG MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID) + MSGF(&MSGFILNAM) MSGFLIB(&MSGFILLIB) SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFILLIB/&MSGFILNAM) + MSGDTA(&MSGDTA) MSGTYPE(*ESCAPE) /* */ /* ----------------------------------------------------------------- */ /* ALL ROADS LEAD TO EXIT */ /* ---------------------- */ /* */ EXIT: RETURN ENDPGM
Source Code - RTVJOBCNT
CMD PROMPT('Count active jobs for user') /* CPP CHGACTJOB */ PARM KWD(JOB) TYPE(*GENERIC) LEN(10) + SPCVAL((*ALL)) MIN(1) PROMPT('Job name:') PARM KWD(USER) TYPE(*NAME) LEN(10) DFT(*ALL) + SPCVAL((*ALL) (*CURRENT)) PROMPT('User + name:') PARM KWD(COUNT) TYPE(*DEC) LEN(8 0) RTNVAL(*YES) + PROMPT('Count of active jobs') /* DEP CTL(&USER *EQ *ALL) PARM((&JOB *NE *ALL)) + NBRTRUE(*EQ 1) MSGID(USR3C01) */
Source Code - RTVJOBC#C
BEGIN: PGM PARM(&JOB &USER &COUNTER) /**/ /* PASSED Variables */ /*------------------- */ /**/ DCL VAR(&JOB) TYPE(*CHAR) LEN(10) + /* Input job name */ DCL VAR(&USER) TYPE(*CHAR) LEN(10) + /* Input user name */ DCL VAR(&COUNTER) TYPE(*DEC) LEN(8 0) /* Counter + Value that will be returned to caller + program */ /* */ /* Local variables */ /* */ /**/ /* PROGRAM Variables */ /*-------------------- */ /**/ DCL VAR(&NUMBER) TYPE(*CHAR) LEN(6) + /* Current job number */ DCL VAR(&USRSPC) TYPE(*CHAR) LEN(20) + VALUE('CHGA QTEMP ') + /* User space name for APIs */ DCL VAR(&EUSRSPC) TYPE(*CHAR) LEN(10) + /* User space name for commands */ DCL VAR(&JOBNAME) TYPE(*CHAR) LEN(26) + VALUE(' *ALL ') + /* Full job name for list job */ DCL VAR(&BIN4) TYPE(*CHAR) LEN(4) + /* Number of jobs for list job and + User space offset in binary 4 form */ DCL VAR(&LOOP) TYPE(*DEC) LEN(8 0) + /* Number of jobs from list job */ /**/ /* Standard Error Handling variables */ /*------------------------------------ */ /**/ DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) /* Error + Message Identifier */ DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(256) /* Error + Message Data */ DCL VAR(&MSGFILNAM) TYPE(*CHAR) LEN(10) /* Error + Message File Name */ DCL VAR(&MSGFILLIB) TYPE(*CHAR) LEN(10) /* Error + Message File Name */ /**/ /* -------------------------------------- */ /* Program Code Starts Here */ /* -------------------------------------- */ /**/ /**/ /* MONITOR FOR UNEXPECTED ERROR MESSAGES */ /* ------------------------------------- */ /**/ MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) /**/ /* Main sections starts here. */ /*------------------------------------------------------------ */ /**/ /**/ /* Retrieve job number to use for local user space name */ /*------------------------------------------------------------ */ /**/ RTVJOBA NBR(&NUMBER) CHGVAR VAR(%SST(&USRSPC 5 6)) VALUE(&NUMBER) CHGVAR VAR(&EUSRSPC) VALUE(%SST(&USRSPC 1 10)) /**/ /* Delete user space if it already exists */ /*------------------------------------------------------------ */ /**/ DLTUSRSPC USRSPC(QTEMP/&EUSRSPC) MONMSG CPF0000 /**/ /* Create user space */ /*------------------------------------------------------------ */ /**/ CALL PGM(QUSCRTUS) PARM(&USRSPC 'RTVJOBCNT ' + X'00000100' ' ' '*ALL ' 'RTVJOBCNT + TEMPORARY USER SPACE ') /**/ /* Setup the job name */ /*------------------------------------------------------------ */ /**/ CHGVAR VAR(%SST(&JOBNAME 1 10)) VALUE(&JOB) CHGVAR VAR(%SST(&JOBNAME 11 10)) VALUE(&USER) /**/ /* List the active jobs with the specified job name */ /*------------------------------------------------------------ */ /**/ CALL PGM(QUSLJOB) PARM(&USRSPC 'JOBL0100' + &JOBNAME '*ACTIVE ') /**/ /* Retrieve the number of entries returned, and convert to decimal */ /*---------------------------------------------------------------- */ /**/ CALL QUSRTVUS (&USRSPC X'00000085' X'00000004' + &BIN4) CHGVAR &LOOP %BINARY(&BIN4) CHGVAR VAR(&COUNTER) VALUE(&LOOP) GOTO CMDLBL(ALLDONE) /**/ /* -------------------------------------- */ /* UNEXPECTED ERROR ROUTINE */ /* -------------------------------------- */ /**/ ERROR: RCVMSG MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID) + MSGF(&MSGFILNAM) MSGFLIB(&MSGFILLIB) SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFILLIB/&MSGFILNAM) + MSGDTA(&MSGDTA) MSGTYPE(*ESCAPE) /**/ /* -------------------------------------- */ /* ALL ROADS LEAD TO EXIT */ /* -------------------------------------- */ /**/ /* */ /* All done. Now delete temporary user space that we created. */ /* */ ALLDONE: DLTUSRSPC USRSPC(QTEMP/&EUSRSPC) MONMSG CPF0000 RETURN ENDPGM