Is My Job Finished?
March 30, 2005 Hey, Ted
From things you have written, I know you understand my need to avoid modifying the packaged software we run. I would like to write a program, to run at night, that will run some in-house programs and then submit some programs from the packaged software to batch. At this point, I need to wait until all the submitted jobs have finished before continuing with some more homegrown programs. How can my overnight program know when the submitted jobs have finished?
–Tim
Isn’t it amazing the lengths we go to in order to avoid modifying packaged software? I’ve put something together you can use. Keep in mind I’ve never used this code in production, so you may run into a problem I never encountered in testing.
Let’s say your overnight program submits three batch jobs.
pgm dcl &MsgDta *char 512 dcl &Job1 *char 26 dcl &Job2 *char 26 dcl &Job3 *char 26 dcl &Delay *dec 5 value(15) /* submit jobs to batch */ SbmJob job(one) Cmd(call pgm1 parm(parm1 parm2 etc.)) RcvMsg MsgType(*comp) MsgDta(&MsgDta) ChgVar &Job1 %sst(&MsgDta 1 26) SbmJob job(two) Cmd(call pgm2 parm(whatever)) RcvMsg MsgType(*comp) MsgDta(&MsgDta) ChgVar &Job2 %sst(&MsgDta 1 26) SbmJob job(three) Cmd(call pgm3 parm(one two three four)) RcvMsg MsgType(*comp) MsgDta(&MsgDta) ChgVar &Job3 %sst(&MsgDta 1 26) /* wait for jobs to finish */ Call WaitForJob parm(&Job1 &Delay) Call WaitForJob parm(&Job2 &Delay) Call WaitForJob parm(&Job3 &Delay) /* the submitted jobs have finished */
The Submit Job (SBMJOB) command sends completion message CPC1221 (Job 111111/SOMEUSER/SOMEJOB submitted to job queue SOMEJOBQ in library SOMELIB). You can use CL’s Receive Message (RCVMSG) command to read this message and extract the job information from it. In this example, I have retrieved the 26-byte qualified job names (each one consisting of simple job name, user, and job number) into variables &JOB1, &JOB2, and &JOB3. Now I know the qualified names of the submitted jobs.
/* CL Program WaitForJob */ pgm parm(&Job &Delay) dcl &Job *char 26 dcl &Delay *dec 5 dcl &RcvVar *char 512 dcl &RcvVarLen *char 4 value(x'0200') dcl &Format *char 10 value('JOBI0100') dcl &JobID *char 16 dcl &JobStatus *char 10 dcl &Abending *lgl dcl &MsgID *char 7 dcl &MsgDta *char 256 dcl &MsgF *char 10 dcl &MsgFLib *char 10 dcl &MsgKey *char 4 dcl &MsgType *char 10 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) /* wait for a job to finish */ ChkStatus: Call QUsrJobI (&RcvVar &RcvVarLen &Format &Job &JobID) MonMsg CPC3C54 Exec(Do) /* job is starting */ ChgVar %sst(&RcvVar 51 10) '*JOBQ' EndDo MonMsg CPC3C53 Exec(Do) /* job is not found */ RcvMsg MsgType(*EXCP) Rmv(*yes) ChgVar %sst(&RcvVar 51 10) ' ' EndDo ChgVar &JobStatus %sst(&RcvVar 51 10) If (&JobStatus *eq '*JOBQ' *or &JobStatus *eq '*ACTIVE') do DlyJob &Delay GoTo ChkStatus EndDo /* normal end of job */ 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
If you look at the example overnight program, you’ll see three calls to WAITFORJOB.
–Ted