Submit Job Schedule Entries Immediately
December 1, 2004 Ted Holt
The code for this article is available for download.
You can buy better job schedulers than the one that comes bundled with OS/400. Unfortunately for many of us, the OS/400 job scheduler is the only one we’re permitted to use. Because I recently found myself forced to work within that restriction, I wrote a command to overcome one of the built-in job scheduler’s limitations. Later I discovered that my new utility overcame a second limitation. It occurred to me that some of you might like to have this utility.
In “Job Scheduler’s Other Defaults,” I explained to Beau that the OS/400 job scheduler runs a Submit Job (SBMJOB) command, filling in certain parameters with non-default values. A problem occurs when someone needs to submit a scheduled job to run outside of the regularly scheduled time. The Work with Job Schedule Entries panel includes option 10, “submit immediately,” which at first seems to address the need, but doesn’t really. The Submit Immediately option runs SBMJOB with SBMJOB’s usual default parameter values, not the non-default parameter values that that the job scheduler uses. This means that the job scheduler does not include an option to immediately submit an entry in the same way the job scheduler normally submits the entry. This is the limitation I needed to overcome.
For this reason, I wrote the Submit Job Schedule Entry (SBMJOBSCDE) utility. It retrieves a job scheduler entry and builds a SBMJOB command, filling in the parameters with the non-default values the job scheduler uses. The utility consists of three objects: the SBMJOBSCDE command, an OPM CL command-processing program named JOBSCDE1C, and a help panel group called JOBSCDE1H.
SBMJOBSCDE is easy to use. It has only two parameters. The first is the name of the entry as it appears in the job scheduler. The second parameter works only in interactive mode. It permits you to prompt the generated SBMJOB command so you can make changes before the new job is submitted to batch. Here’s the source code.
/* ==================================================== */ /* Submit a job schedule entry for immediate execution. */ /* ==================================================== */ /* To create: */ /* CRTCMD CMD(xxx/SBMJOBSCDE) */ /* PGM(xxx/JOBSCDE1C) */ /* SRCFILE(xxx/QCMDSRC) */ /* HLPPNLGRP(JOBSCDE1H) */ /* HLPID(*CMD) */ /* ==================================================== */ CMD PROMPT('Submit Job Schedule Entry') PARM KWD(JOB) TYPE(*CHAR) LEN(10) MIN(1) + EXPR(*YES) PROMPT('Job schedule entry name') PARM KWD(PROMPT) TYPE(*CHAR) LEN(4) RSTD(*YES) + DFT(*NO) VALUES(*YES *NO) EXPR(*YES) + PROMPT('Prompt before submitting?')
The CL program uses the List Job Schedule Entries (QWCLSCDE) API to retrieve the job schedule entry information into user space QTEMP/SBMJOBSCDE. It extracts that information from the user space to build the SBMJOB command.
/* ==================================================== */ /* Submit a job schedule entry for immediate execution. */ /* ==================================================== */ /* To compile: */ /* CRTCLPGM PGM(xxx/JOBSCDE1C) */ /* SRCFILE(xxx/QCLSRC) */ /* SRCMBR(JOBSCDE1C) */ /* ==================================================== */ pgm parm(&inJobScdE &inPrompt) dcl &inJobScdE *char 10 dcl &inPrompt *char 4 dcl &UsrSpcName *char 10 'SBMJOBSCDE' dcl &UsrSpcLib *char 10 'QTEMP' dcl &UsrSpc *char 20 dcl &FmtName *char 8 'SCDL0200' dcl &NbrEntries *dec 10 dcl &Offset *dec 10 dcl &EntryLen *dec 10 dcl &Continue *char 16 dcl &StartPos *dec 5 dcl &UsrSpcData *char x'1000' dcl &UsrSpcSize *char 4 x'00001000' dcl &Error *char 16 x'00000010' dcl &JobType *char 1 dcl &Cmd *char 512 dcl &CmdLen *dec 3 dcl &InfoStatus *char 1 dcl &JobName *char 10 dcl &JobQ *char 10 dcl &JobQLib *char 10 dcl &JobD *char 10 dcl &JobDLib *char 10 dcl &MsgQ *char 10 dcl &MsgQLib *char 10 dcl &UsrPrf *char 10 dcl &CmdString *char 4096 dcl &Quote *char 1 '''' dcl &Abending *lgl dcl &MsgID *char 7 dcl &MsgDta *char 256 dcl &MsgF *char 10 dcl &MsgFLib *char 10 dcl &MsgKey *char 4 dcl &RtnType *char 2 dcl &PgmName *char 10 dcl &Sender *char 80 monmsg cpf0000 exec(goto abend) /* retrieve the program name */ sndpgmmsg msg(' ') topgmq(*same) msgtype(*info) keyvar(&MsgKey) rcvmsg pgmq(*same) msgtype(*info) sender(&Sender) rmv(*yes) chgvar &PgmName %sst(&Sender 56 10) /* create a temporary user space */ /* and load it with job schedule information */ chgvar &UsrSpc (&UsrSpcName *cat &UsrSpcLib) chkobj &UsrSpcLib/&UsrSpcName *usrspc monmsg cpf0000 exec(do) call quscrtus (&UsrSpc ' ' &UsrSpcSize ' ' *all &Error) enddo call qwclscde (&UsrSpc &FmtName &inJobScdE &Continue &Error) call qusrtvus (&UsrSpc x'00000001' &UsrSpcSize &UsrSpcData &Error) chgvar &NbrEntries %bin(&UsrSpcData 133 4) if (&NbrEntries *lt 1) do chgvar var(&MsgDta) value('Job schedule entry' *bcat &inJobScdE + *bcat 'could not be found.') sndpgmmsg msgid(cpf9897) msgf(qcpfmsg) msgtype(*diag) + msgdta(&MsgDta) goto Escape enddo /* extract job info from the job schedule entry */ chgvar &Offset %bin(&UsrSpcData 125 4) chgvar &EntryLen %bin(&UsrSpcData 137 4) chgvar &StartPos (&Offset + 1) chgvar &InfoStatus %sst(&UsrSpcData &StartPos 1) chgvar &StartPos (&Offset + 2) chgvar &JobName %sst(&UsrSpcData &StartPos 10) chgvar &StartPos (&Offset + 198) chgvar &JobQ %sst(&UsrSpcData &StartPos 10) chgvar &StartPos (&Offset + 208) chgvar &JobQLib %sst(&UsrSpcData &StartPos 10) chgvar &StartPos (&Offset + 527) chgvar &JobD %sst(&UsrSpcData &StartPos 10) chgvar &StartPos (&Offset + 537) chgvar &JobDLib %sst(&UsrSpcData &StartPos 10) chgvar &StartPos (&Offset + 547) chgvar &UsrPrf %sst(&UsrSpcData &StartPos 10) chgvar &StartPos (&Offset + 557) chgvar &MsgQ %sst(&UsrSpcData &StartPos 10) chgvar &StartPos (&Offset + 567) chgvar &MsgQLib %sst(&UsrSpcData &StartPos 10) chgvar &StartPos (&Offset + 641) chgvar &CmdLen %bin(&UsrSpcData &StartPos 4) chgvar &StartPos (&Offset + 645) chgvar &Cmd %sst(&UsrSpcData &StartPos &CmdLen) /* Was prompting requested? */ rtvjoba type(&JobType) if (&JobType *eq '1') do /* Interactive job */ if ((%sst(&inPrompt 2 1) *eq 'Y') + *or (%sst(&inPrompt 2 1) *eq 'y')) do chgvar &CmdString '?' enddo enddo /* build a command string from the job schedule entry */ chgvar &CmdString (&CmdString *tcat 'SBMJOB JOB(' + *cat &JobName *tcat ')') chgvar &CmdString (&CmdString *bcat 'JOBD(') if (%sst(&JobD 1 1) *ne '*') do chgvar &CmdString (&CmdString *tcat &JobDLib *tcat '/') enddo chgvar &CmdString (&CmdString *tcat &JobD *tcat ')') chgvar &CmdString (&CmdString *bcat 'JOBQ(') if (%sst(&JobQ 1 1) *ne '*') do chgvar &CmdString (&CmdString *tcat &JobQLib *tcat '/') enddo chgvar &CmdString (&CmdString *tcat &JobQ *tcat ')') chgvar &CmdString (&CmdString *bcat 'CMD(' + *cat %sst(&Cmd 1 &CmdLen) + *cat ')') chgvar &CmdString (&CmdString *bcat 'USER(' *cat &UsrPrf *cat ')') chgvar &CmdString (&CmdString *bcat 'MSGQ(') if (%sst(&MsgQ 1 1) *ne '*') do chgvar &CmdString (&CmdString *tcat &MsgQLib *tcat '/') enddo chgvar &CmdString (&CmdString *tcat &MsgQ *tcat ')') chgvar &CmdString (&CmdString *bcat 'SYSLIBL(*SYSVAL) + CURLIB(*USRPRF) INLLIBL(*JOBD) + PRTDEV(*JOBD) OUTQ(*JOBD) + PRTTXT(*JOBD) RTGDTA(*JOBD) + SRTSEQ(*USRPRF) LANGID(*USRPRF) + CNTRYID(*USRPRF) CCSID(*USRPRF)') call qcmdexc (&CmdString 4096) monmsg cpf6801 rcvmsg msgtype(*last) msgdta(&MsgDta) msgid(&MsgID) + rtntype(&RtnType) + msgf(&MsgF) sndmsgflib(&MsgFLib) sndpgmmsg msgid(&MsgID) msgf(&MsgF) msgtype(*comp) + msgdta(&MsgDta) return /* Routine to handle unexpected errors */ Abend: if &Abending then(return) chgvar &Abending '1' ForwardMsg: rcvmsg msgtype(*any) msgdta(&MsgDta) msgid(&MsgID) + rtntype(&RtnType) + msgf(&MsgF) sndmsgflib(&MsgFLib) if ((&RtnType *eq '02') *or /* diagnostic */ + (&RtnType *eq '15') *or (&RtnType *eq '17')) do /* *escape */ sndpgmmsg msgid(&MsgID) msgf(&MsgF) msgtype(*diag) + msgdta(&MsgDta) enddo if (&RtnType *ne ' ') then(goto ForwardMsg) Escape: sndpgmmsg msgid(cpf9898) msgf(qcpfmsg) msgtype(*escape) + msgdta('Program' *bcat &PgmName *bcat + 'ended abnormally') endpgm
The command is easy enough to use, but I put together some brief help text anyway. Store it in member JOBSCDE1H.
.* ==================================================================== .* Help text for the SBMJOBSCDE command .* ==================================================================== .* To create: .* CRTPNLGRP PNLGRP(xxx/JOBSCDE1H) .* SRCFILE(xxx/QPNLSRC) .* SRCMBR(JOBSCDE1H) .* ==================================================================== :PnlGrp. :Help Name = 'SBMJOBSCDE' .Submit Job Schedule Entry - Help :P. The Submit Job Schedule Entry (SBMJOBSCDE) command allows you to submit a job scheduler entry using the parameter values the job scheduler applies to the SBMJOB command. SBMJOBSCDE allows you to run a scheduled job on demand in the same way it would run if the job scheduler started it. :EHelp. :Help Name = 'SBMJOBSCDE/Job' .Job name (JOB) - Help :XH3 .Job entry (JOB) :P. The name of the job as it is known to the job scheduler. :P. This is a required parameter. :EHelp. :Help Name = 'SBMJOBSCDE/PROMPT' .Prompt command (PROMPT) - Help :XH3 .Prompt command (PROMPT) :P. This parameter applies to interactive execution of SBMJOBSCDE only. It allows you to modify the generated SBMJOB comamnd before submitting the job to batch for execution. :P. The possible values are: :Parml. :pt.:pk def.*NO:epk. :pd.SBMJOB will not be prompted before execution. :pt.:pk.*YES:epk. :pd.SBMJOB will be prompted for execution. You will be allowed to modify parameter values. :EParmL. :EHelp. :EPnlGrp.
I mentioned that my new utility overcame a second limitation. After I wrote SBMJOBSCDE, I realized I had found the answer to the problem I wrote about in “Scheduling a Job to Run More than Once a Day.” In a follow-up to that article, reader Rocky suggested creating multiple, identical job schedule entries in order to run a job schedule entry more than once a day. The problem with that approach is that changing one entry means having to change them all.
SBMJOBSCDE addresses this problem as well. Create one entry with the proper settings. Make the others run SBMJOBSCDE to kick off the original entry at other times.
So far I have been pleased with SBMJOBSCDE. This utility has worked correctly in all my tests and in production. I hope some of you will find it helpful as well. Please contact me with bug reports or suggestions for improvements, if you have a better idea, or just to let me know it’s helped you.
Ted Holt is editor of Four Hundred Guru. Click here to contact Ted Holt by e-mail.