Listing jobs called in a Sequence Job (automatically)

A forum for discussing DataStage<sup>®</sup> basics. If you're not sure where your question goes, start here.

Moderators: chulett, rschirm, roy

Post Reply
joycerecacho
Participant
Posts: 298
Joined: Tue Aug 26, 2008 12:17 pm

Listing jobs called in a Sequence Job (automatically)

Post by joycerecacho »

Hi everyone!

I would like to know how could I automatically list the names of the jobs that are called in a Sequence job.

Thank you very much.

Best regards,
Joyce A. Recacho
São Paulo/SP
Brazil
chulett
Charter Member
Charter Member
Posts: 43085
Joined: Tue Nov 12, 2002 4:34 pm
Location: Denver, CO

Post by chulett »

The dssearch command comes to mind. An exact search here for it should turn up conversations to that effect.
-craig

"You can never have too many knives" -- Logan Nine Fingers
ray.wurlod
Participant
Posts: 54607
Joined: Wed Oct 23, 2002 10:52 pm
Location: Sydney, Australia
Contact:

Post by ray.wurlod »

There is a log entry called "Summary of Sequence Run" near the end of the sequence's log.

Otherwise you need to create a recursive routine. I have one somewhere - I'll see if I can dig it out.
IBM Software Services Group
Any contribution to this forum is my own opinion and does not necessarily reflect any position that IBM may hold.
joycerecacho
Participant
Posts: 298
Joined: Tue Aug 26, 2008 12:17 pm

Post by joycerecacho »

Ray,
In DS designer, If we click on 'properties' (right button on the job name), it opens a windows with a sheet called 'Dependencies'.
There you can also find the job names that the Sequence calls, but since there are many of them, the idea is something not that manual, otherwise I would have to copy and paste one by one.

Thanks!

Best regards,
Joyce A. Recacho
São Paulo/SP
Brazil
chulett
Charter Member
Charter Member
Posts: 43085
Joined: Tue Nov 12, 2002 4:34 pm
Location: Denver, CO

Post by chulett »

<cough> dssearch </cough>
-craig

"You can never have too many knives" -- Logan Nine Fingers
ray.wurlod
Participant
Posts: 54607
Joined: Wed Oct 23, 2002 10:52 pm
Location: Sydney, Australia
Contact:

Post by ray.wurlod »

OK, I've dug out the routine I was thinking of. Note that it's a recursive routine, so I hope you don't have hierarchies of sequences hundreds of sequences deep!

The code is provided "as is".

Code: Select all

      FUNCTION TraceSequence(aSequenceName,aLevel)
$COPYRIGHT "Copyright (C) 2008, Ray Wurlod.  All rights reserved."
$IFNDEF JOBCONTROL.H
$INCLUDE DSINCLUDE JOBCONTROL.H
$ENDIF
      DEFFUN TraceSequence(Arg1, Arg2) Calling "DSU.TraceSequence"     ; * for recursive calls
      DEFFUN GetLinkRowCounts(Arg1) Calling "DSU.GetLinkRowCounts"

      Begin Case

         Case UnAssigned(aSequenceName)
            Ans = @NULL

         Case IsNull(aSequenceName)
            Ans = @NULL

         Case Trim(aSequenceName) <= " "
            Ans = @NULL

         Case @TRUE

            hJob = DSAttachJob(aSequenceName, DSJ.ERRNONE)
            JobName = DSGetJobInfo(hJob, DSJ.JOBNAME)

            If JobName = DSJE.BADHANDLE
            Then

               Ans = DSJE.BADHANDLE
               Call DSLogWarn("Unable to attach to job sequence " : Quote(aSequenceName), "TraceSequence")

            End
            Else

               ****************************************************************************************************
               * Construct full job name, including invocation ID of multi-instance job if any.
               ****************************************************************************************************

               FullJobName = JobName
               InvocationID = DSGetJobInfo(hJob,DSJ.JOBINVOCATIONID)
               If Len(InvocationID)
               Then
                  FullJobName = FullJobName : "." : InvocationID
               End


               ****************************************************************************************************
               * Determine job type (server, mainframe, sequence, parallel).
               ****************************************************************************************************

               JobTypeInd = Trans("DS_JOBS", JobName, 6, "X") + 0
               If aLevel = 0 Then Ans = ""


               ****************************************************************************************************
               * Process job type appropriately.  Row counts only for jobs, recursion for sequences.
               * If job finish date/time not reported by DSGetJobInfo() look in the job log.
               * Link row counts obtained by routine GetLinkRowCounts.
               ****************************************************************************************************

               Begin Case

                  Case JobTypeInd = 0    ; * server job

                     JobStart = DSGetJobInfo(hJob, DSJ.JOBSTARTTIMESTAMP)
                     JobFinish = DSGetJobInfo(hJob, DSJ.JOBLASTTIMESTAMP)
                     If Not(JobFinish)
                     Then
                        JobFinish = "(unreported)"
                        FinishEventID = DSGetNewestLogId(hJob, DSJ.LOGSTARTED)
                        FinishEvent = DSGetLogEntry(hJob, FinishEventID)
                        If FinishEvent Then JobFinish = Field(FinishEvent, "\\", 1, 1)
                     End
                     Ans = (If aLevel > 0 Then "   " Else "") : "Server Job " : Quote(FullJobName) : " started " : JobStart
                     Gosub DecodeJobStatus
                     If JobExitStatus <> DSJS.RUNNING
                     Then
                        Ans := ", at " : JobFinish : "."
                        LinkRowCounts = GetLinkRowCounts(FullJobName)
                        Ans := "   Records processed = "
                        Ans := Field(LinkRowCounts, "~", 1, 1) : " input, "
                        Ans := Field(LinkRowCounts, "~", 2, 1) : " output, "
                        Ans := Field(LinkRowCounts, "~", 3, 1) : " reject, "
                        Ans := Field(LinkRowCounts, "~", 4, 1) : " insert, "
                        Ans := Field(LinkRowCounts, "~", 5, 1) : " update, "
                        Ans := Field(LinkRowCounts, "~", 6, 1) : " upsert, "
                        Ans := Field(LinkRowCounts, "~", 7, 1) : " delete"
                     End

                  Case JobTypeInd = 1    ; * mainframe job (should never be executed on UNIX)

                     JobStart = DSGetJobInfo(hJob, DSJ.JOBSTARTTIMESTAMP)
                     JobFinish = DSGetJobInfo(hJob, DSJ.JOBLASTTIMESTAMP)
                     If Not(JobFinish)
                     Then
                        JobFinish = "(unreported)"
                        FinishEventID = DSGetNewestLogId(hJob, DSJ.LOGSTARTED)
                        FinishEvent = DSGetLogEntry(hJob, FinishEventID)
                        If FinishEvent Then JobFinish = Field(FinishEvent, "\\", 1, 1)
                     End
                     Ans = (If aLevel > 0 Then "   " Else "") : "Mainframe Job " : Quote(FullJobName) : " started " : JobStart
                     Gosub DecodeJobStatus
                     If JobExitStatus <> DSJS.RUNNING
                     Then
                        Ans := ", at " : JobFinish : "."
                        LinkRowCounts = GetLinkRowCounts(FullJobName)
                        Ans := "   Records processed = "
                        Ans := Field(LinkRowCounts, "~", 1, 1) : " input, "
                        Ans := Field(LinkRowCounts, "~", 2, 1) : " output, "
                        Ans := Field(LinkRowCounts, "~", 3, 1) : " reject, "
                        Ans := Field(LinkRowCounts, "~", 4, 1) : " insert, "
                        Ans := Field(LinkRowCounts, "~", 5, 1) : " update, "
                        Ans := Field(LinkRowCounts, "~", 6, 1) : " upsert, "
                        Ans := Field(LinkRowCounts, "~", 7, 1) : " delete"
                     End

                  Case JobTypeInd = 2    ; * sequence job

                     JobStart = DSGetJobInfo(hJob, DSJ.JOBSTARTTIMESTAMP)
                     JobFinish = DSGetJobInfo(hJob, DSJ.JOBLASTTIMESTAMP)
                     If Not(JobFinish)
                     Then
                        JobFinish = "(unreported)"
                        FinishEventID = DSGetNewestLogId(hJob, DSJ.LOGSTARTED)
                        FinishEvent = DSGetLogEntry(hJob, FinishEventID)
                        If FinishEvent Then JobFinish = Field(FinishEvent, "\\", 1, 1)
                     End

                     EventIDs = DSGetLogEventIds(hJob, 0, "S")         ; * list of log event IDs for current run
                     StartEventID = Field(EventIDs, "\\", 1, 1)
                     FinishEventID = Field(EventIDs, "\\", 2, 1)

                     Ans = "Sequence " : Quote(FullJobName) : " started " : JobStart
                     Gosub DecodeJobStatus
                     If JobExitStatus <> DSJS.RUNNING
                     Then
                        Ans := " at " : JobFinish : "."
                     End

                     For EventID = StartEventID To FinishEventID
                        Entry = DSGetLogEntry(hJob, EventID)
                        If Index(Entry, "Job run requested", 1)
                        Then
                           SubJob = Field(Field(Entry, ")", 1, 1), "(", 2, 1)
                           SubJobInfo = TraceSequence(SubJob, aLevel + 1)        ; * recursive call
                           Ans<-1> = Str("   ",aLevel) : SubJobInfo
                        End
                     Next


                  Case JobTypeInd = 3    ; * parallel job

                     JobStart = DSGetJobInfo(hJob, DSJ.JOBSTARTTIMESTAMP)
                     JobFinish = DSGetJobInfo(hJob, DSJ.JOBLASTTIMESTAMP)
                     If Not(JobFinish)
                     Then
                        JobFinish = "(unreported)"
                        FinishEventID = DSGetNewestLogId(hJob, DSJ.LOGSTARTED)
                        FinishEvent = DSGetLogEntry(hJob, FinishEventID)
                        If FinishEvent Then JobFinish = Field(FinishEvent, "\\", 1, 1)
                     End
                     Ans = (If aLevel > 0 Then "   " Else "") : "Parallel Job " : Quote(FullJobName) : " started " : JobStart
                     Gosub DecodeJobStatus
                     If JobExitStatus <> DSJS.RUNNING
                     Then
                        Ans := ", at " : JobFinish : "."
                        LinkRowCounts = GetLinkRowCounts(FullJobName)
                        Ans := "   Records processed = "
                        Ans := Field(LinkRowCounts, "~", 1, 1) : " input, "
                        Ans := Field(LinkRowCounts, "~", 2, 1) : " output, "
                        Ans := Field(LinkRowCounts, "~", 3, 1) : " reject, "
                        Ans := Field(LinkRowCounts, "~", 4, 1) : " insert, "
                        Ans := Field(LinkRowCounts, "~", 5, 1) : " update, "
                        Ans := Field(LinkRowCounts, "~", 6, 1) : " upsert, "
                        Ans := Field(LinkRowCounts, "~", 7, 1) : " delete"
                     End

               End Case

            End

      End Case

      RETURN(Ans)

DecodeJobStatus:
      JobExitStatus = DSGetJobInfo(hJob, DSJ.JOBSTATUS)
      Begin Case
         Case JobExitStatus = DSJS.RUNNING
            Ans := "  Running"
         Case JobExitStatus = DSJS.RUNOK
            Ans := "  Finished OK"
         Case JobExitStatus = DSJS.RUNWARN
            Ans := "  Finished with warning(s)"
         Case JobExitStatus = DSJS.RUNFAILED
            Ans := "  Aborted"
         Case JobExitStatus = DSJS.VALOK
            Ans := "  Validated OK"
         Case JobExitStatus = DSJS.VALWARN
            Ans := "  Validated with warning(s)"
         Case JobExitStatus = DSJS.VALFAILED
            Ans := "  Validation failed"
         Case JobExitStatus = DSJS.RESET
            Ans := "  Has been reset"
         Case 1
            Ans := "  Status not determined."
      End Case

      RETURN(Ans)

      RETURN(Ans)
You'll also need GetLinkRowCounts() function.

Code: Select all

FUNCTION GetLinkRowCounts(aJobName)
$COPYRIGHT "Copyright (C) 2008, Ray Wurlod.  All rights reserved."
* Returns tilde-delimited list of link row counts based on link name suffix: "_IN", "_OUT", "_REJ", "_INS", "_UPD", "_UPS", "_DEL"
* Note that the routine assumes that there is only one of each.

$IFNDEF JOBCONTROL.H
$INCLUDE DSINCLUDE JOBCONTROL.H
$ENDIF
$UNDEFINE TESTING


**********************************************************************************************************************
*     Initialise variables.
**********************************************************************************************************************

      RoutineName = "GetLinkRowCounts"
      Ans = "0~0~0~0~0~0~0"
      Temp = Convert("~", @FM, Ans)

**********************************************************************************************************************
*     Attach job whose name was given as routine argument.
**********************************************************************************************************************

      hJob = DSAttachJob(aJobName, DSJ.ERRNONE)

      ActualJobName = DSGetJobInfo(hJob, DSJ.JOBNAME)
      If ActualJobName = DSJE.BADHANDLE
      Then

         Call DSLogWarn("Could not attach job " : Quote(aJobName) : ".", RoutineName)

      End
      Else

         LinksSeen = ""                  ; * list of link names already processed

**********************************************************************************************************************
*        Obtain a list of stage names in the job and convert to dynamic array for REMOVE processing.
**********************************************************************************************************************

         StageList = DSGetJobInfo(hJob, DSJ.STAGELIST)       ; * comma-delimited list of stage names
$IFDEF TESTING
call DSLogInfo('StageList:  ': StageList ,'Debug')
$ENDIF
         Convert "," To @FM In StageList           ; * convert to dynamic array

         Loop
            Remove StageName From StageList Setting MoreStages         ; * process stages one at a time.
$IFDEF TESTING
Call DSLogInfo("Processing stage " : Quote(StageName), "Testing")
$ENDIF

**********************************************************************************************************************
*           Obtain a list of link names attached to the current stage and convert to dynamic array.
**********************************************************************************************************************

            LinkList = DSGetStageInfo(hJob, StageName, DSJ.LINKLIST)   ; * comma-delimited list of link names
$IFDEF TESTING
call DSLogInfo('StageName:  ': StageName ,'Debug')
call DSLogInfo('LinkList:  ': LinkList ,'Debug')
$ENDIF
            Convert "," To @FM In LinkList         ; * convert to dynamic array

            Loop
               Remove LinkName From LinkList Setting MoreLinks

**********************************************************************************************************************
*              Check to see whether link already processed.  If not add link to name list and process the link.
**********************************************************************************************************************

               Locate LinkName In LinksSeen By "AL" Setting Seen
               Else


                  Ins LinkName Before LinksSeen<Seen>

                  LinkNameSuffix = "_" : Field(LinkName, "_", Count(LinkName, "_") + 1, 1)
                  Begin Case

                     Case LinkNameSuffix = "_IN"   ; * Input
                        Temp<1> += DSGetLinkInfo(hJob, StageName, LinkName, DSJ.LINKROWCOUNT)

                     Case LinkNameSuffix = "_OUT"  ; * Output
                        Temp<2> += DSGetLinkInfo(hJob, StageName, LinkName, DSJ.LINKROWCOUNT)

                     Case LinkNameSuffix = "_REJ"  ; * Reject output
                        Temp<3> += DSGetLinkInfo(hJob, StageName, LinkName, DSJ.LINKROWCOUNT)

                     Case LinkNameSuffix = "_INS"  ; * Insert
                        Temp<4> += DSGetLinkInfo(hJob, StageName, LinkName, DSJ.LINKROWCOUNT)

                     Case LinkNameSuffix = "_UPD"  ; * Update
                        Temp<5> += DSGetLinkInfo(hJob, StageName, LinkName, DSJ.LINKROWCOUNT)

                     Case LinkNameSuffix = "_UPS"  ; * Upsert
                        Temp<6> += DSGetLinkInfo(hJob, StageName, LinkName, DSJ.LINKROWCOUNT)

                     Case LinkNameSuffix = "_DEL"  ; * Delete
                        Temp<7> += DSGetLinkInfo(hJob, StageName, LinkName, DSJ.LINKROWCOUNT)

                  End Case               ; * it is possible to exit this Case construct without having processed a count

               End                       ; * end of Locate statement

            While MoreLinks
            Repeat                       ; * end of Links loop


         While MoreStages
         Repeat                          ; * end of Stages loop

         Ignore = DSDetachJob(hJob)

         Ans = Convert(@FM, "~", Temp)

      End
RETURN(Ans)
IBM Software Services Group
Any contribution to this forum is my own opinion and does not necessarily reflect any position that IBM may hold.
kduke
Charter Member
Charter Member
Posts: 5227
Joined: Thu May 29, 2003 9:47 am
Location: Dallas, TX
Contact:

Post by kduke »

Very nice looking code.
Mamu Kim
ray.wurlod
Participant
Posts: 54607
Joined: Wed Oct 23, 2002 10:52 pm
Location: Sydney, Australia
Contact:

Post by ray.wurlod »

The result of the routine (the Ans variable) contains the list of dependent jobs. Do with this what you will. Perhaps modify the routine to write to a file as Ans is appended to.

Note, however, that this routine returns design time information - that is, jobs that MAY be called from the sequence depending on the sequence's logic.

To get the jobs that are ACTUALLY called, refer to the "summary of sequence run" in the sequence's job log. If you want to do this in a routine, use the DSGetLog... calls.
IBM Software Services Group
Any contribution to this forum is my own opinion and does not necessarily reflect any position that IBM may hold.
Post Reply